深入浅出JVM内存结构及GC机制

JVM内存结构

JAVA运行时的数据区:根据 JVM 规范,JVM在执行JAVA程序的过程中会把它所管理的内存分为虚拟机栈、本地方法栈、程序计数器(PC寄存器)、堆、方法区五个部分。

深入浅出JVM内存结构及GC机制

深入浅出JVM内存结构及GC机制

深入浅出JVM内存结构及GC机制

JVM中对象的生命周期图如下:

深入浅出JVM内存结构及GC机制

新生代:系统启动后,新创建的存放在Eden区中,一段时间后,大量的对象存放在Eden区中,导致Eden满了,触发YongGC,所采用复制算法。回收掉大量的对象。存活下来的对象被全部移动到幸存区中的From区(或者TO区),并在存活下来的对象上标记 +1。待下一次Eden区满的时候,再次触发YongGC,回收掉Eden区大量的对象,存活下来的对象全部移动到TO区(或者From),刚移动到TO区的对象标记+1,而从From区移动到TO的对象标记 +2。每经历过一次YongGC 对象都会标记 +1 。下面循环往复。只有Eden区满了, 就会进行一次YongGC, 然后把存活下来的对象移动到幸存区。 只要幸存区中的对象经历过15次(此值大小可设置)YongGC后,待下次再经历YongGC直接移动到Old区。

备注: 默认Eden:S0:S1=8:1:1

默认 new:old =1:2

老年代:Full GC 是发生在老年代的垃圾收集动作,所采用的是标记-清除算法。设置一个参数开启标记整理算法,每次执行FullGC后,都会执行一次标记整理算法。老年代里面的对象几乎个个都是在 Survivor 区域中熬过来的,它们是不会那么容易就 “死掉” 了的。因此,Full GC 发生的次数不会有 Minor GC 那么频繁,并且做一次 Full GC 要比进行一次 Minor GC 的时间更长。 另外,标记-清除算法收集垃圾的时候会产生许多的内存碎片 ( 即不连续的内存空间 ),此后需要为较大的对象分配内存空间时,若无法找到足够的连续的内存空间,就会提前触发一次 GC 的收集动作。

深入浅出JVM内存结构及GC机制

深入浅出JVM内存结构及GC机制

性能调优重要参数

1.JVM运行时堆的大小

-Xms堆的初始大小

-Xmx堆空间的最大值

2.新生代堆空间大小调整

-XX:NewSize新生代的最小值

-XX:MaxNewSize新生代的最大值

-XX:NewRatio设置新生代与老年代在堆空间的大小

-XX:SurvivorRatio新生代中Eden所占区域的大小

3、其他

-XX:MaxTenuringThreshold,设置将新生代对象转到老年代时需要经过多少次垃圾回收,但是仍然没有被回收

-XX:CMSInitiatingOccupancyFraction=70:表示年老代内存空间使用到70%时就开始执行CMS收集,确保年老代有足够的空间接纳来自年轻代的对象,避免Full GC的发生。

-XX:+UseCMSCompactAtFullCollection:打开内存空间的压缩和整理,在Full GC后执行。可能会影响性能,但可以消除内存碎片。

JVM监控命令

(一) jmap –heap pid:打印heap的概要信息,heap的配置及使用情况。

(二) jstat –gc/-gcutil pid interval count:Heapsize和垃圾回收状况的监控

(三) java -XX:+PrintFlagsFinal -version > jvmpara.txt

讨论区

(一)为什么要把大对象不经过新生代直接放进老年代?

(二)老年代垃圾收集后碎片问题

因为年老代的并发收集器使用标记清除算法,所以不会对堆进行压缩。当收集器回收时,他会把相邻的空间进行合并,这样可以分配给较大的对象。但是,当堆空间较小时,运行一段时间以后,就会出现“碎片”,如果并发收集器找不到足够的空间,那么并发收集器将会停止,然后使用传统的标记、清除方式进行回收。

如果出现“碎片”,可能需要进行如下配置:

-XX:+UseCMSCompactAtFullCollection:使用并发收集器时,开启对年老代的压缩。

-XX:CMSFullGCsBeforeCompaction=0:上面配置开启的情况下,这里设置多少次Full GC后,对年老代进行压缩。

所谓大对象,是指需要大量连续内存空间的java对象,例如很长的数组,此种对象会直接进入老年代,而老年代虽然有很大的剩余空间,但是无法找到足够大的连续空间来分配给当前对象,此种情况就会触发JVM进行Full GC。

CMS和Parnew只是一种垃圾回收算法,Parnew作用在新生代,CMS则作用在老年代。

为了解决这个问题,CMS垃圾收集器提供了一个可配置的参数,

Concurrent Mark Sweep(并行标记清除),是一种以获取最短回收停顿时间为目标的收集器,尤其重视服务的响应速度。

CMS是老年代垃圾回收器,基于标记-清除算法实现。新生代默认使用ParNew并行收集器,基于复制算法

即-XX:+UseCMSCompactAtFullCollection开关参数,用于在“享受”完Full GC服务之后额外免费赠送一个碎片整理的过程,内存整理的过程无法并发的,空间碎片问题没有了,但提顿时间不得不变长了,JVM设计者们还提供了另外一个参数 -XX:CMSFullGCsBeforeCompaction,这个参数用于设置在执行多少次不压缩的Full GC后,跟着来一次带压缩的。

(三)什么情况下回触发MinorGC 、FullGC?

Minor GC触发条件:当Eden区满时,触发Minor GC。

Full GC触发条件:

(1)调用System.gc时,系统建议执行Full GC,但是不必然执行

(2)老年代空间不足(老年代的使用率达到阈值(通过JVM参数:CMSInitiatingOccupancyFraction设定,默认为92%))

(3)方法去空间不足

(4)通过Minor GC后进入老年代的平均大小大于老年代的可用内存

(5)由Eden区、From Space区向To Space区复制时,对象大小大于To Space可用内存,则把该对象转存到老年代,且老年代的可用内存小于该对象大小。

1、为了避免由于新生代对象晋升到旧生代导致旧生代空间不足的现象,在进行Minor GC时,做了一个判断,如果之前统计所得到的Minor GC晋升到旧生代的平均大小大于旧生代的剩余空间,那么就直接触发Full GC。

例如程序第一次触发Minor GC后,有6MB的对象晋升到旧生代,那么当下一次Minor GC发生时,首先检查旧生代的剩余空间是否大于6MB,如果小于6MB,则执行Full GC。

2、对于采用CMS进行老年代GC的程序而言,尤其要注意GC日志中是否有promotion failed和concurrent mode failure两种状况,当这两种状况出现时可能会触发Full GC。

promotion failed是在进行Minor GC时,survivor space放不下、对象只能放入老年代,而此时老年代也放不下造成的;

concurrent mode failure是在执行CMS GC的过程中同时有对象要放入老年代,而此时老年代空间不足造成的

优化方法:增大survivor space、老年代空间


分享到:


相關文章: