您的位置:首页 > 其它

垃圾回收机制(GC)原理以及jvm调优知识

2017-07-05 17:44 543 查看

垃圾回收机制

1. 内存的组成:堆(Heap)和非堆(Non-heap)内存。

堆是运行时数据区域,是由new分配的内存,因为不知道大小的,应该有程序自己来申请内存空间,所以由堆来分配是留给开发人员使用的;

非堆就是JVM留给自己用的。

2. JVM初始分配的内存由-Xms指定,默认是物理内存的1/64;JVM最大分配的内存由-Xmx指
定,默认是物理内存的1/4。默认空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制;空余堆内存大于70%时,JVM会减少堆直到-Xms的最小限制。因此服务器一般设置-Xms、-Xmx相等以避免在每次GC后调整堆的大小。(这个在后边jvm调优会用到)。

3. 看张图片:堆内存分配(跟后边说到的GC原理还有jvm调优参数相关联)





4. 非堆内存分配

JVM使用-XX:PermSize设置非堆内存初始值,默认是物理内存的1/64;由XX:MaxPermSize设置最大非堆内存的大小,默认是物理内存的1/4。

 


上边名词的定义和解释,其实跟接下来要说的垃圾回收机制采用的方法相关:

JVM里的GC(Garbage Collection)的算法有很多种,这里就说最常用的一种,分代收集算法。

5. 分代收集算法将内存分为几个区域,将不同生命周期的对象放在不同区域里:young generation,tenured
generation和permanet generation。绝大部分的object被分配在young
generation(生命周期短),并且大部分的object在这里die。当young
generation满了之后,将引发minor collection(YGC)。在minor
collection后存活的object会被移动到tenured
generation(生命周期比较长)。最后,tenured
generation满之后触发major collection。major
collection(Full gc)会触发整个heap的回收,包括回收young
generation。permanet generation区域比较稳定,主要存放classloader信息。

6. young generation有eden、2个survivor区域组成。其中一个survivor区域一直是空的,是eden区域和另一个survivor区域在下一次copy
collection后(YGC)活着的object的目的地。object在survivo区域被复制直到转移到tenured区。

7. 我们要尽量减少 Full gc的次数(tenured
generation一般比较大,收集的时间较长,频繁的Full
gc会导致应用的性能收到严重的影响)。

8. 堆内存GC:JVM(采用分代回收的策略),用较高的频率对年轻的对象(young
generation)进行YGC,而对老对象(tenured
generation)较少(tenured
generation 满了后才进行)进行Full GC。这样就不需要每次GC都将内存中所有对象都检查一遍。

9. 非堆内存不GC:GC不会在主程序运行期对PermGen
Space进行清理,所以如果你的应用中有很多CLASS(特别是动态生成类,当然permgen
space存放的内容不仅限于类)的话,就很可能出现PermGen
Space错误。

至此:GC的执行流程基本就说完了。接下来,看一些jvm的配置参数,通过配置可以防止GC后出现卡顿的现象。

10. 再说一个项目中的问题:

promotion failed: 垃圾回收时promotion failed是个很头痛的问题,一般可能是两种原因产生,第一个原因是救助空间不够,救助空间里的对象还不应该被移动到年老代,但年轻代又有很多对象需要放入救助空间;第二个原因是年老代没有足够的空间接纳来自年轻代的对象;这两种情况都会转向Full
GC,网站停顿时间较长。

再换一种说法:promontion faild产生的原因是EDEN空间不足的情况下将EDEN与From
survivor中的存活对象存入To survivor区时,To survivor区的空间不足,再次晋升到old
gen区,而old gen区内存也不够的情况下产生了promontion faild从而导致full
gc.那可以推断出:eden+from survivor < old gen区剩余内存时,不会出现promontion faild的情况。即如下公式:

(Xmx-Xmn)*(1-CMSInitiatingOccupancyFraction/100)>=(Xmn-Xmn/(SurvivorRatior+2))这个不难理解。

进而推断出:

CMSInitiatingOccupancyFraction <=((Xmx-Xmn)-(Xmn-Xmn/(SurvivorRatior+2)))/(Xmx-Xmn)*100。

CMSInitiatingOccupancyFraction低于80%需要调整xmn或SurvivorRatior值。

11.网上推荐的jvm配置的最优方案(仅供参考)

-Xmx256M//最大堆大小

-Xms256M //初始堆大小

-Xmn96M //年轻代大小Sun官方推荐配置为整个堆的3/8

-XX:PermSize=500M //设置持久代(perm gen)初始值
非堆内存

-XX:MaxPermSize=500M //设置持久代最大值 --------XMX和XMS设置一样大,MaxPermSize和MinPermSize设置一样大,这样可以减轻伸缩堆大小带来的压力。

-Xss256K //每个线程的堆栈大小

-XX:+DisableExplicitGC //关闭System.gc(),免得程序员误调用gc方法影响性能

-XX:SurvivorRatio=1 //Eden区与Survivor区的大小比值(计算公式)

-XX:+UseConcMarkSweepGC //使用CMS内存收集(使用CMS的好处是用尽量少的新生代,经验值是128M-256M,
然后老生代利用CMS并行收集, 这样能保证系统低延迟的吞吐效率。 实际上cms的收集停顿时间非常的短,2G的内存,
大约20-80ms的应用程序停顿时间)

-XX:+UseParNewGC //设置年轻代为并行收集(使用CMS的好处是用尽量少的新生代,经验值是128M-256M,
然后老生代利用CMS并行收集, 这样能保证系统低延迟的吞吐效率。 实际上cms的收集停顿时间非常的短,2G的内存,
大约20-80ms的应用程序停顿时间)。

-XX:+CMSParallelRemarkEnabled // 降低标记停顿

-XX:+UseCMSCompactAtFullCollection //在FULL GC的时候,对年老代的压缩 消除碎片1

-XX:CMSFullGCsBeforeCompaction=0 //
多少次后进行内存压缩2

-XX:+CMSClassUnloadingEnabled

-XX:LargePageSizeInBytes=128M //内存页的大小不可设置过大, 会影响Perm的大小

-XX:+UseFastAccessorMethods //原始类型的快速优化

-XX:+UseCMSInitiatingOccupancyOnly //使用手动定义初始化定义开始CMS收集,禁止hostspot自行触发CMS
GC

-XX:CMSInitiatingOccupancyFraction=80 //使用cms作为垃圾回收 使用80%后开始CMS收集

-XX:SoftRefLRUPolicyMSPerMB=0 //每兆堆空闲空间中SoftReference的存活时间

-XX:+PrintClassHistogram

-XX:+PrintGCDetails

-XX:+PrintGCTimeStamps

-XX:+PrintHeapAtGC //打印GC前后的详细堆栈信息
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  GC jvm 垃圾回收机制