JVM虚拟机深度讲解

JVM虚拟机深度讲解

JVM虚拟机深度讲解

1.类加载子系统与方法区:类加载子系统负责从文件系统或者网络中加载class信息(classload就是这个系统下一个组件),加载的类信息存放于一块称为方法区的内存空间(classload通过io把class文件里面的字节加载到虚拟机中要保存起来,class文件里面的字节会保存到方法区)。除了类的信息外,方法区中可能还会存放运行时常量池信息,包括字符串字面量和数字常量(这部分常量信息是class文件中常量池部分的内存映射),常量池,放定义的常量,唯一的一份都在这里放着,方法区里放的都是唯一的东西。通过类加载子系统将class文件加载进来放到方法区里,并且将里面的常量信息都存进来。

2.java堆:java堆在虚拟机启动时建立,它是java程序最主要的内存工作区域。几乎所有的java对象实例都存放在java堆中。堆空间是所有线程共享的,这是一块与java应用密切相关的内存空间。

3.直接内存:java的NIO库允许java程序使用直接内存。直接内存是在java堆外的、直接向系统申请的内存空间。通常访问直接内存的速度会优于java堆。因此出于性能的考虑,读写频繁的场合可能会考虑使用直接内存。由于直接内存在java堆外,因此它的大小不会直接受限于Xmx(堆的指令,Xmx一个指令)指定的最大堆大小,但是系统内存是有限的,java堆和直接内存的总和依然受限于操作系统能给出的最大内存。直接内存不属于java堆,java堆的大小由jvm控制的,而直接内存是直接映射到物理位置上的,它理论上的空间是无限的,不受jvm的控制,但是实际上它的大小限制取决于物理内存大小。

**4.垃圾回收系统:**是java虚拟机的重要组成部分,垃圾回收器可以对方法区、java堆和直接内存进行回收。其中,java堆 是垃圾收集器的工作重点。和C/C++不同,java中所有的对象空间释放都是隐式的,也就是说,java中没有类似于free(或者delete)这样的函数释放指定的内存区域。对于不再使用的垃圾对象,垃圾回收系统会在后台默默工作,默默查找、标识并释放垃圾对象,完成包括java堆、方法区和直接内存中的全自动化管理。

5.java栈:每一个java虚拟机线程都有一个私有的java栈,一个线程的java栈在线程创建的时候被创建,java栈中保存着帧信息,java栈中保存着局部变量、方法参数,(栈空间独立的,完全隔离,不共享的)同时和java方法的调用、返回密切相关。

6.本地方法栈:和java栈类似,最大的不同在于java栈用于方法的调用,而本地方法栈用于本地方法的调用(调操作系统的API,操作系统里的API在JVM里就称为本地方法,为什么不同的操作系统提供了不同版本的JVM呢?就是因为在这块位置不通用,不同操作系统的API的结构或方法不一样,为了让虚拟机适应所有的操作系统,就得写多个虚拟机调不同操作系统里的不同的本地方法来完成各种操作,如果所有的操作系统的本地方法都相同,则虚拟机有一份就行了。作为对java虚拟机的重要扩展,java虚拟机允许java直接调用本地方法(通常使用C编写)。

7.pc(program counter):pc寄存器也是每一个线程私有的空间,java虚拟机会为每一个java线程创建pc寄存器。在任意时刻,一个java线程总是在执行一个方法(线程无时无刻都在执行方法,不执行方法这个线程就死掉了),这个正在被执行的方法称为当前方法。如果当前方法不是本地方法,pc寄存器就会指向当前正在被执行的指令。如果当前方法是本地方法,那么pc寄存器的值就是undefined(pc寄存器更多的是用来区分线程里执行的方法是本地方法还是java自己的方法的一个作用)

8.执行引擎:是java虚拟机最核心的组件之一,它负责执行虚拟机的字节码,现代虚拟机为了提高执行效率,会使用即时编译技术(just in time)将方法编译成机器码再执行。

java HotSpot Client VM(-client),为在客户端环境中减少启动时间而优化。

java HotSpot Server VM(-server),为在服务器环境中最大化程序执行速度而设计。

java HotSpot Client模式和Server模式的区别:

当虚拟机运行在-client模式的时候,使用的是一个代号为C1的轻量级编译器,而-server模式启动的虚拟机采用相对重量级,代号为C2的编译器。C2比C1编译器编译的相对彻底,服务起来后性能更高。

重点:在部分JDK1.6版本后,-client参数已经失效了,Server模式成为唯一。

jvm堆结构图及分代:

java虚拟机:JVM内存分代策略

java虚拟机根据对象存活的周期不同,把堆内存分为几块,一般分为新生代、老年代和永久代(对HotSpot虚拟机而言),这就是JVM的内存分代策略。

为什么要分代?

堆内存是虚拟机管理的内存中最大的一块,也是垃圾回收最频繁的一块区域,我们程序所有的对象实例都存放在堆内存中,给堆内存分代是为了提高对象内存分配和垃圾回收的效率。试想一下,如果堆内存没有区域划分,所有的新创建的对象和生命周期很长的对象放在一起,随着程序的执行,堆内存需要频繁进行垃圾收集,而每次回收都要遍历所有的对象,遍历这些对象所花费的时间代价是巨大的,会严重影响我们的GC效率。

有了内存分代,情况就不同了,新创建的对象会在新生代中分配内存,经过多次回收仍然存活下来的对象存放在老年代中,静态属性、类信息等存放在永久代中,新生代中的对象存活时间短,只需要在新生代区域中频繁进行GC,老年代中对象生命周期长,内存回收的频率相对较低,不需要频繁进行回收,永久代中回收效果太差,一般不进行垃圾回收,还可以根据不同年代的特点采用合适的垃圾收集算法。分代收集大大提升了收集效率,这些都是内存分代带来的好处。

内存分代划分

java虚拟机将堆内存划分为新生代、老年代和永久代,永久代是HotSpot虚拟机特有的概念,它采用永久代的方式来实现方法区,其他的虚拟机实现没有这一概念,而且HotSpot也有取消永久代的趋势,在JDK1.7中HotSpot已经开始了“去永久化”,把原本放在永久代的字符串常量池移出。(堆里永久代所存放的东西跟方法区里存的东西很相似,都是生命周期很长的,有的还具备唯一性,所有可以把这些东西移植到方法区去存储,这样能节省堆内存空间)永久代主要存放常量、类信息、静态变量等数据,与垃圾回收关系不大,新生代和老年代是垃圾回收的主要区域。java堆内存分代示意图如下:

JVM虚拟机深度讲解

新生代(Young Generation)

新生成的对象优先存放在新生代中,新生代对象朝生夕死,存活率很低,在新生代中,常规应用进行一次垃圾收集一般可以回收70%到95%的空间,回收效率很高。

HotSpot将新生代划分为三块,一块较大的Eden空间和两块较小的Survivor空间,默认比例为8:1:1。划分的目的是因为HotSpot采用复制算法来回收新生代,设置这个比例是为了充分利用内存空间,减少浪费。新生代的对象在Eden区分配(大对象除外,大对象直接进入老年代),当Eden区没有足够的空间进行分配时,虚拟机将发起一次Minor GC。GC开始时,对象只会存在于Eden区和From Survivor区,To Survivor区是空的(作为保留区域)。GC进行时,Eden区中所有存活的对象都会被复制到To Survivor区,而在From Survivor区中,仍存活的对象会根据它们的年龄值决定去向,年龄值达到年龄阀值(默认为15,新生代中的对象每熬过一轮垃圾回收,年龄值就加1,GC分代年龄存储在对象的header中)的对象会被移到老年代中,没有达到阀值的对象会被复制到To Survivor区。接着清空Eden区和From Survivor区,新生代中存活的对象都在To Survivor区。接着,From Survivor区和To Survivor区会交换它们的角色,也就是新的To Survivor区就是上次GC清空的From Survivor区,新的From Survivor区就是上次GC的To Survivor区,总之,不管怎样都会保证TO Survivor区在一轮GC后是空的。GC时当To Survivor区没有足够的空间存放上一次新生代收集下来的存活对象时,需要依赖老年代进行分配担保,将这些对象存放在老年代中。

老年代(Old Generation)

在新生代中经历了多次(具体看虚拟机配置的阀值)GC后仍然存活下来的对象会进入老年代中。老年代中的对象生命周期较长,存活率比较高,在老年代中进行GC的频率相对而言较低,而且回收的速度也比较慢。

永久代(Permanent Generation)

永久代存储类信息、常量、静态变量、即时编译器编译后的代码等数据,对这一区域而言,java虚拟机规范指出可以不进行垃圾收集,一般而言不会进行垃圾回收。在JDK1.7中HotSpot已经开始了“去永久化”

jvm垃圾回收算法及收集器:

垃圾回收常见算法:(有很多)

1.引用计数(Reference Counting):

比较古老的回收算法,原理是此对象有一个引用,即增加一个计数,删除一个引用则减少一个计数。垃圾回收时,只收集计数为0的对象。此算法最致命的是无法处理循环引用的问题。对象刚创建出来,就给个引用计数,有引用就加一,这个对象赋新的引用就加一,一个对象可以被多个引用指向,断一个引用就减一。

2.复制(Copying):

此算法把内存空间划为两个相等的区域,每次只使用其中一个区域。垃圾回收时,遍历当前使用区域,把正在使用的对象复制到另外一个区域中。此算法每次只处理正在使用中的对象,因此复制成本比较小,同时复制过去以后还能进行相应的内存整理,不会出现“碎片”问题,此算法的缺点是需要两倍内存空间。

3.标记-清除(Mark-Sweep):

此算法执行分两阶段。第一阶段从引用根节点开始标记所有被引用的对象(从这个对象的根开始为它和它所关联的对象做标记),第二阶段遍历整个堆,把未标记的对象清除(若这个对象没有被标记则为空对象,有标记说明有线连着它,有引用指向它,代表这个对象正在使用的,这个对象没有被标记说明是无用的对象就要对它做回收)。此算法需要暂停整个应用(所有用户线程都得停止,不能说边收集你边使用内存空间往里面放对象),同时会产生内存碎片。(未使用得空间不连续,不连续就是碎片会影响到存储)这是垃圾回收最古老得算法,接下来的所有算法都是对这个算法的暂停整个应用和产生内存碎片进行优化。

JVM虚拟机深度讲解

4.标记-整理(Mark-Compact):

此算法结合了“标记-清除”和“复制”两个算法的优点。也是分两个阶段,第一阶段从根节点开始标记所有被引用对象,第二阶段遍历整个堆,把清除未标记对象并且把存活对象“压缩”到堆的其中一块,按顺序排放(就能解决碎片问题),此算法避免了“标记清除”的碎片问题,同时也避免了“复制”算法的空间问题。标记-整理算法其实就是对标记-清除算法的一个优化。

JVM虚拟机深度讲解

jvm中垃圾收集器

垃圾回收算法就是决定对垃圾回收的一种方式,这种方式需要有具体的代码或程序去执行。垃圾收集器与垃圾回收算法的关系:如果说垃圾回收算法是垃圾回收的方法论,那么垃圾收集器就是对垃圾回收方法论的具体实现,就是对该方法的具体实现。

Scavenge GC(次收集)和Full GC的区别(全收集)

新生代GC(Scavenge GC):Scavenge GC指发生在新生代的GC,因为新生代的java对象大多都是朝生夕死,所以Scavenge GC非常频繁,一般回收速度也比较快。当Eden空间不足以为对象分配内存时,会触发Scavenge GC。

一般情况下,当新对象生成,并且在Eden申请空间失败时,就会触发Scavenge GC,对Eden区域进行GC,清除非存活对象,并且把尚且存活的对象移动到Survivor区。然后整理Survivor的两个区。这种方式的GC是对年轻代的Eden区进行,不会影响到老年代。(Scavenge GC只影响年轻代)因为大部分对象都是从Eden区开始的,同时Eden区不会分配的很大,所以Eden区的GC会频繁进行。一般在这里需要使用速度快、效率高的算法,使Eden区能尽快空闲出来。

老年代GC(Full GC或叫Major GC):Full GC指发生在老年代的GC,出现了Full GC一般会伴随着至少一次的Minor GC(老年代的对象大部分是Minor GC过程中从新生代进入老年代,Full GC前面肯定进行了多次Minor GC(次GC),Minor GC优先于Full GC),比如:分配担保失败。Full GC的速度一般会比Minor GC慢10倍以上。当老年代内存不足或者显示调用System.gc()方法时,会触发Full GC。

次收集:

当年轻代堆空间紧张时会被触发,相对于全收集而言,收集间隔较短。

全收集:

当老年代或者持久代堆空间满了,会触发全收集操作。

可以使用System.gc()方法来启动全收集Full GC,全收集一般根据堆大小的不同,需要的时间不相同,但一般会比较长,不会超过3秒钟。

分代垃圾回收器:

JVM虚拟机深度讲解

新生代收集器:

串行收集器(Serial)

Serial收集器是Hotspot运行在Client模式下的默认的新生代收集器,它的特点是只用一个CPU/一条收集线程去完成GC工作,且在进行垃圾收集时必须暂停其他所有的工作线程。

JVM虚拟机深度讲解

并行收集器(ParNew):

JVM虚拟机深度讲解

Parallel Scavenge收集器:

JVM虚拟机深度讲解

JVM虚拟机深度讲解

老年代收集器:

Serial Old收集器:

JVM虚拟机深度讲解

Parallel Old收集器:

Parallel Old是Parallel Scavenge收集器老年代版本,使用多线程和“标记-整理”算法,吞吐量优先,主要与Parallel Scavenge配合在系统内使用。

CMS收集器:

JVM虚拟机深度讲解

JVM虚拟机深度讲解

JVM虚拟机深度讲解

分区收集-G1收集器:

JVM虚拟机深度讲解

JVM优化

JVM小工具

JVM虚拟机深度讲解

JVM虚拟机深度讲解

JVM虚拟机深度讲解

JVM虚拟机深度讲解

JVM参数介绍

JVM虚拟机深度讲解

JVM虚拟机深度讲解

常见配置举例:

堆大小设置:

JVM虚拟机深度讲解

JVM虚拟机深度讲解

JVM虚拟机深度讲解

吞吐量优先的并行收集器:

JVM虚拟机深度讲解

JVM虚拟机深度讲解

JVM虚拟机深度讲解

调优总结:

JVM虚拟机深度讲解

JVM虚拟机深度讲解

JVM虚拟机深度讲解