马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
一、JVM概述
目次
一、JVM概述
1.jvm的作用
2.jvm的构成
2.1类加载
2.1.1加载
2.1.2链接
2.1.3初始化
2.1.4类加载器分类
2.1.5双亲委派机制
2.2运行时数据区
2.2.1步调计数器
2.2.2假造机栈
2.2.3当地方法栈
2.2.4java堆内存
2.2.5方法区
2.3当地方法库接口
2.4实验引擎
2.4.1表明器
2.4.2JIT编译器
2.4.3半表明半编译
2.5垃圾采取
2.5.1早期的垃圾采取
2.5.2java的垃圾采取
2.5.3垃圾采取的地区
2.5.4垃圾采取算法
2.5.5垃圾采取器
1.jvm的作用
将.class字节码文件装载,编译表明为该平台对应的呆板码。jvm不光可以加载java的字节码文件还可以加载其他语言的字节码文件。
2.jvm的构成
jvm的团体组因素为以下四个部分
1.类加载器(ClassLoder)
2.运行时数据区(Runtime Data Area)
3.实验引擎(Excute Engine)
4.当地库接口(Native Interface)
2.1类加载
类加载体系从文件体系或网络中加载class文件,而是否可以运行由实验引擎决定。
2.1.1加载
使用流将硬盘上的字节码读取到内存中(运行时数据区)的方法区中,天生对象的class对象
2.1.2链接
验证:验证字节码格式是否精确,查抄class字节码文件是否被窜改
准备:为静态变量赋默认值,如static int a = 123;此时a被赋予int范例默认值0;
剖析:将字节码中符号引用更换成直接引用,(符号引号就是字节码中的逻辑符号,直接引用就是内存地点)
2.1.3初始化
当类完成初始化,即代表这个类加载完成。
初始化过程中重要有以下功能,1.初始化类中静态变量;2.实验静态代码块;如果有父类,则从父类开始递归初始化。初始化过程中是在实验底层构造方法<client>(),该方法是由编译器天生的。
什么时间初始化?(即类什么时间被加载)
1.使用类中的静态成员,如调用类中的静态方法,静态变量
2.运行类中的main方法
3.new该类的对象
4.加载该类的子类
5.通过反射机制 Class.forName()
有以下两种情况不会被初始化
1.使用类中的静态常量
2.使用该类创建一个数组对象
2.1.4类加载器分类
引导类加载器(启动类加载器,bootstrap classloder)
这个类加载器用语言和C++实现,嵌套在jvm内部,负责加载java焦点库中的类。如java.lang、java.util、java.math、java.io、java.sql等包中的类。
扩展类加载器(extension classloder)
这个类加载器由java语言实现,用于加载java8\jre\lib\ext 目次下的类
应用步调类加载器(application classloder)
这个类加载器由java语言实现,用于加载我们自界说的类。
2.1.5双亲委派机制
该机制是指在类加载过程中,会先由上级的类加载器举行加载,如果找不到该类,则逐级由下面的类加载器加载,如果找不到类则抛出ClassNotFoundException非常。该机制是须要的,可以有用地防止用户自界说的类由于地点名重复而覆盖源代码的类。
2.2运行时数据区
作用:运行时数据区是java步调运行时,jvm存储数据和管理步调实验的内存地区。
固然各假造机的运行时数据区略有差异,但是都是满意java假造机的规范的,java8假造机规定,运行时数据区包罗以下地区:1.方法区;2.堆;3.步调计数器;4.当地方法栈;5.假造机栈
2.2.1步调计数器
作用: 步调计数器是用来纪录当火线程中实验的指令的位置
步调计数器特点:
步调计数器是用来纪录当火线程中实验的指令的位置,因此每个线程都有一个步调计数器,步调计数器是线程私有的;
步调计数器占用内存小,实验速率快;
步调计数器随线程而生,随线程而死;
步调计数器不存在内存溢出的情况。
2.2.2假造机栈
作用:假造机栈是java实验方法的地区
假造机栈的特点:
假造机栈中步调可以实验java方法,属于运行结构,每个线程都会有一个假造机栈,因此假造机栈也是线程私有的。
当栈中实验的方法过多时,会出现栈溢出非常。
栈运行特点,先辈后出/后进先出
方法被调用事后,在栈中称为栈帧,栈帧内部包罗局部变量表,表达式栈,方法返回地点
局部变量表中存储方法中的参数和方法内部的局部变量,根本数据范例直接存值,引用范例则存储对象的引用。
表达式栈举行方法中的全部盘算过程。
当一个方法实验完毕之后,要返回之前调用它的地方,因此在栈帧中必须生存一个方法返回地点。
2.2.3当地方法栈
作用:当地方法栈重要用来运行被调用的当地方法(用native修饰的方法,由操纵体系实现的c++/c语言方法)
2.2.4java堆内存
作用:堆是用来存储运行时产生的全部对象。
堆的特点:
堆是java内存管理的最大地区,是jvm中内存最大的地区。堆的内存巨细是可以调治的(运行时数据区中除了步调计数器的巨细不可以调解以外,其他均可以通过jvm调优来调解巨细)。比方:-Xms:10m(堆起始巨细)-Xmx:30m(堆最大内存巨细)。
java产生的全部对象都在堆中存储
全部的线程共享堆内存
堆空间会发生内存溢出
堆中是垃圾采取的重要地区
堆的空间分区:
堆分为新生区和老年区,新生区又分为伊甸园区和幸存者区,幸存者区又分为幸存者0区和幸存者1区。
对象在堆中的分配过程:新产生的对象起首存放在伊甸园区,在第一次GC后,全部未被采取的对象会被转移到幸存者0区;在第二次GC后,伊甸园区和幸存者0区的全部对象会被转移到幸存者1区;再次举行GC后,伊甸园区和幸存者1区的全部对象都会转移到幸存者0区,云云循环往复,直到对象的GC次数高出15次,就会被转移到老年区,老年区的对象就相对稳固,GC的频率会较低。大概当对象较大时也会被送到老年区。
堆空间分区的须要性:对堆空间举行分区是须要的,通过对对象在堆中举行分区,来调解GC对对象的扫描频率,从而进步GC的服从。
设置堆空间的参数:
-Xms:初始堆空间内存
-Xmx:最大堆空间内存
-Xmn:设置新生代的巨细
-XX:MaxTenuringTreshold:设置新生代垃圾的最大年事
2.2.5方法区
作用:方法区重要用来储存加载到内存中的类信息,也会存储静态方法和变量及即时编译器编译的代码
方法区特点:
方法区物理上和堆处于同一个空间,但是逻辑上会对其举行区分,我们又称方法区为元空间
方法区巨细是可以设置的,通过对:MetaspaceSize=<N>参数举行修改, 方法区一旦空间不敷,会触发FULL GC(整堆网络),会影相应用步调线程,一样寻常情况下,可以把方法区设置较大一点
方法区存在内存溢出
方法区存在垃圾采取
方法区中的类什么时间会被采取?
想要对方法区中的类举行采取,须要满意以下三个条件:
1.方法区中该类及其全部子类的实例都不存在
2.加载该类的类加载器不存在了
3.该类的Class对象不存在了
2.3当地方法库接口
作用:当地库接口是一个编程框架,可以让java代码与其他语言编写的代码举行交互,即让java步调调用当地方法(c语言或c++)。
什么是当地方法:当地方法就是用native关键字修饰的方法
为什么要调用当地方法:当地方法可以与操纵体系上的硬件举行交互,而java属于应用步调语言,没有权限操纵硬件装备。
- new Object().hashCode(); //public native int hashCode(); 获取内存地址
- new FileInputStream("").read(); //private native int read0() 读硬盘数据
- new Thread().start();// private native void start0(); 把线程注册到操作系统
复制代码 2.4实验引擎
作用:实验引擎(excution engine)的作用是将字节码文件表明/编译为对应平台上的呆板语言。其充当了高级语言和呆板语言之间的翻译官。
2.4.1表明器
表明就是对字节码逐行表明成呆板码的过程,该过程相应速率快,步调运行就可以投入使用,但是逐行表明服从较低。
2.4.2JIT编译器
编译就是对字节码团体编译后实验,编译须要耗费肯定时间,但是服从高。JIT编译器会对热门代码举行编译后缓存,以后使用时就不须要举行编译操纵了。
2.4.3半表明半编译
java是半表明半编译语言,如许计划既可以在步调运行之处使用表明的特点立刻实验,也能通过编译操纵提拔服从。
2.5垃圾采取
什么是垃圾:垃圾就是步调运行过程中没有任何引用能访问到的对象。
整理垃圾:如果不及时对垃圾举行整理,就会导致堆内存溢出。由于垃圾会不绝占据内存知到步调运行竣事。
内存溢出:内存溢出就是内存不敷用了,但是尚有新的对象产生,于是步调抛出非常。
内存走漏:内存走漏是由于某些对象步调已经不再使用了,但由于某些缘故因由仍存在应用,GC无法对其举行采取,比方数据库毗连对象,网络Socket对象。
Stop The World(STW):在GC过程中,会将应用步调的线程制止,发生短暂的卡顿。
finalize机制:java中的Object类提供了一个finalize()方法,这个方法是在对象被判断为垃圾后,在被采取之前主动被垃圾采取器调用的方法。该方法是针对对象的,只能被调用一次。如果在第一次的finalize()方法中将本标志为垃圾对象复活(为其重新指向引用),则第二次垃圾采取时就不会调用finalize()方法了。
对象的分类:
1.可触及:没有被判断为垃圾对象
2.可复活:被判断为垃圾对象,但是还没调用过finalize()方法。
3.不可触及:第二次被判断为垃圾对象。
2.5.1早期的垃圾采取
早期的C和C++都是手动申请内存,手动开释内存。此种设定可以精确地管理内存,使用时申请,不须要时就开释。但是会给步调员带来较大的负担,一旦忘记开释内存,就会产生内存走漏。
2.5.2java的垃圾采取
java采取的是主动垃圾采取,解放了步调员,不消再关心什么时间开释空间。
2.5.3垃圾采取的地区
堆是垃圾采取的重点地区,对堆中的新生代会频仍举行GC操纵,较少对老年区GC。方法区由于类加载信息采取较为苛刻,须要比及FULL GC(整堆采取)。
2.5.4垃圾采取算法
2.5.4.1垃圾标志阶段的算法
1.引用计数算法(Reference Counting)
对每个对象都有一个引用计数的属性,当引用计数为0时,表现该对象已不存在引用指向他,便标志为垃圾。然而该方法有个致命缺点,就是无法办理循环引用题目,从而导致内存走漏。
2.可达性分析算法
该方法从生动对象开始向下探求,与生动对象相毗连的都是被使用的,而未与生动对象毗连的就是垃圾对象。
生动对象包罗:
1.假造机栈中方法使用的对象;
2.引用范例静态变量
- static Object globalVariable = new Object(); // 静态变量是GC Root
复制代码 3.全部被同步锁持有的对象
4.jvm内部的引用对象,如常驻的非常对象,类加载器等。
2.5.4.2正式采取阶段算法
1.标志复制算法:
标志复制算法可以有多个内存空间,会将地区中的有用对象团体复制到其他地区中,然后将原来地区中的对象全部打扫。通常实用于采取新生区。由于新生区中垃圾较多,须要复制的对象较少。
2.标志打扫算法
该算法只须要一块内存,会将被标志为垃圾的对象直接打扫,但是采取后会导致内存碎片化,实用于老年区,老年区中垃圾较少。
内存碎片化的危害
总空闲内存充足,但缺乏连续的大块内存,导致无法满意大对象的分配需求。
3.标志压缩算法
该方法只须要用到一块内存,会将被标志的对象删除后,再对剩余对象举行移动,防止产生碎片化地区。
分代网络
年轻代的对象,存活的少,垃圾多,使用标志复制算法举行采取
老年代的对象大,且存活时间长,采取标志打扫和标志压缩算法举行采取
优化垃圾采取服从
2.5.5垃圾采取器
1.分类:
垃圾采取器按线程数分为:
单线程(串行)Serial
多线程(并行)Parallel 垃圾采取器。
从工作模式上分为:
独占式的: 当垃圾采取线程在实验时,其他用户线程停息(STW)
并发式的: 垃圾采取线程和用户线程可以同时实验, 淘汰了用户线程停息的次数和时间,并未完全不存在STW。
按照工作内存分为:
新生代垃圾网络器
老年代垃圾网络器
jdk8支持的垃圾采取器:
|