JVM1.6 GC详解
前言
JVM GC是JVM的内存回收算法,调整JVM GC(Garbage Collection),可以极大的减少由于GC工作,而导致的程序运行中断方面的问题,进而适当的提高Java程序的工作效率。但是调整GC是以个极为复杂的过程,所以我们要了解JVM内存组成,回收算法,对象分配机制。
JVM 堆内存组成
Java堆由Perm区和Heap区组成,Heap区由Old区和New区(也叫Young区)组成,New区由Eden区、From区和To区(Survivor)组成。

Eden区用于存放新生成的对象。Eden中的对象生命不会超过一次Minor GC。
Survivor Space 有两个,存放每次垃圾回收后存活的对象,即图的S0和S1。
Old Generation Old区,也称老生代,主要存放应用程序中生命周期长的存活对象
JVM初始分配的内存由-Xms指定,JVM最大分配的内存由-Xmx指定。默认空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制;空余堆内存大于70%时,JVM会减少堆直到 -Xms的最小限制。因此服务器一般设置-Xms、-Xmx相等以避免在每次GC 后调整堆的大小。
-XX:NewRatio= 参数可以设置Young与Old的大小比例,-server时默认为1:2,如果太小,会使大对象直接分配到old区去,增大major collections的执行的次数,影响性能。
-XX:SurvivorRatio= 参数可以设置Eden与Survivor的比例,默认为1:8,Survivio大了会浪费,如果小了的话,会使一些大对象在做minor gc时,直接从eden区潜逃到old区,让old区的gc频繁。这个参数保持默认就好了,一般情况下,对性能影响不大。
New区的Collector
1、 串行GC(Serial Copying)
client模式下的默认GC方式,也可使用-XX:+UseSerialGC指定。
2、 并行回收GC(Parallel Scavenge)
server模式下的默认GC方式,也可用-XX:+UseParallelGC强制指定。
采用PS时,默认情况下JVM会在运行时动态调整Eden:S0:S1的比例,如果不希望自动调整可以使用-XX:-UseAdaptiveSizePolicy参数,内存分配和回收的算法和串行相同,唯一不同仅在于回收时为多线程。
3、 并行GC(ParNew)
CMS GC时默认采用,也可以采用-XX:+UseParNewGC指定。内存分配、回收和PS相同,不同的仅在于会收拾会配合CMS做些处理。
Old区的几种Collector
1、 串行GC(Serial MSC)
client模式下的默认GC方式,可通过-XX:+UseSerialGC强制指定。每次进行全部回收,进行Compact,非常耗费时间。
2、 并行GC(Parallel MSC)(备注,吞吐量大,但是gc的时候响应很慢)
server模式下的默认GC方式,也可用-XX:+UseParallelGC=强制指定。可以在选项后加等号来制定并行的线程数。
3、 并发GC(CMS)线上环境采用的GC方式,也就是Realese环境的方式。(备注,响应比并行gc快很多,但是牺牲了一定的吞吐量)
使用CMS是为了减少GC执行时的停顿时间,垃圾回收线程和应用线程同时执行,可以使用-XX:+UseConcMarkSweepGC=指定使用,后边接等号指定并发线程数。CMS每次回收只停顿很短的时间,分别在开始的时候(Initial Marking),和中间(Final Marking)的时候,第二次时间略长。具体CMS的过程可以参考相关文档。JStat中将Initial Mark和Remark都统计成了FGC。
CMS一个比较大的问题是碎片和浮动垃圾问题(Floating Gabage)。碎片是由于CMS默认不对内存进行Compact所致,可以通过-XX:+UseCMSCompactAtFullCollection。
总体来讲,Old区的大小较大,垃圾回收算法较费时间,导致较长时间的应用线程停止工作,而且需要进行Compact,所以不应该出现较多Major GC。Major GC的时间常常是Minor GC的几十倍。JVM内存调优的重点,减少Major GC 的次数,因为为Major GC 会暂停程序比较长的时间,如果Major GC 的次数比较多,意味着应用程序的JVM内存参数需要进行调整。
JVM内存分配策略
1. 对象优先在Eden分配
如果Eden区不足分配对象,会做一个minor gc,回收内存,尝试分配对象,如果依然不足分配,才分配到Old区。
2.大对象直接进入老年代
大对象是指需要大量连续内存空间的Java对象,最典型的大对象就是那种很长的字符串及数组,虚拟机提供了一个-XX:PretenureSizeThreshold参数,令大于这个设置值的对象直接在老年代中分配。这样做的目的是避免在Eden区及两个Survivor区之间发生大量的内存拷贝(新生代采用复制算法收集内存)。PretenureSizeThreshold参数只对Serial和ParNew两款收集器有效,
3.长期存活的对象将进入老年代
在经历了多次的Minor GC后仍然存活:在触发了Minor GC后,存活对象被存入Survivor区在经历了多次Minor GC之后,如果仍然存活的话,则该对象被晋升到Old区。
虚拟机既然采用了分代收集的思想来管理内存,那内存回收时就必须能识别哪些对象应当放在新生代,哪些对象应放在老年代中。为了做到这点,虚拟机给每个对象定义了一个对象年龄(Age)计数器。如果对象在Eden出生并经过第一次Minor GC后仍然存活,并且能被Survivor容纳的话,将被移动到Survivor空间中,并将对象年龄设为1。对象在Survivor区中每熬过一次Minor GC,年龄就增加1岁,当它的年龄增加到一定程度(默认为15岁)时,就会被晋升到老年代中。对象晋升老年代的年龄阈值,可以通过参数-XX:MaxTenuringThreshold来设置。
4.动态对象年龄判定
为了能更好地适应不同程序的内存状况,虚拟机并不总是要求对象的年龄必须达到MaxTenuringThreshold才能晋升老年代,如果在Survivor空间中相同年龄所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象就可以直接进入老年代,无须等到MaxTenuringThreshold中要求的年龄。
5.Minor GC后Survivor空间不足就直接放入Old区
6.空间分配担保
在发生Minor GC时,虚拟机会检测之前每次晋升到老年代的平均大小是否大于老年代的剩余空间大小,如果大于,则改为直接进行一次Full GC。如果小于,则查看HandlePromotionFailure设置是否允许担保失败;如果允许,那只会进行Minor GC;如果不允许,则也要改为进行一次Full GC。大部分情况下都还是会将HandlePromotionFailure开关打开,避免Full GC过于频繁。
JVM GC组合方式

如何监视GC
1.概览监视gc。
jmap -heap [pid] 查看内存分布
jstat -gcutil [pid] 1000 每隔1s输出java进程的gc情况
2.详细监视gc。
在jvm启动参数,加入-verbose:gc -XX:+PrintGCTimeStamps -XX:+PrintGCDetails -Xloggc:./gc.log。
输入示例:
[GC [ParNew: 11450951K->1014116K(11673600K), 0.8698830 secs] 27569972K->17943420K(37614976K), 0.8699520 secs] [Times: user=11.28 sys=0.82, real=0.86 secs]
表示发生一次minor GC,ParNew是新生代的gc算法,11450951K表示eden区的存活对象的内存总和,1014116K表示回收后的存活对象的内存总和,11673600K是整个eden区的内存总和。0.8699520 secs表示minor gc花费的时间。
27569972K表示整个heap区的存活对象总和,17943420K表示回收后整个heap区的存活对象总和,37614976K表示整个heap区的内存总和。
[Full GC [Tenured: 27569972K->16569972K(27569972K), 180.2368177 secs] 36614976K->27569972K(37614976K), [Perm : 28671K->28635K(28672K)], 0.2371537 secs]
表示发生了一次Full GC,整个JVM都停顿了180多秒,输出说明同上。只是Tenured: 27569972K->16569972K(27569972K)表示的是old区,而上面是eden区。
更多可以参考 阿里分享的ppt sunjdk1.6gc.pptx
JVM1.6 GC详解的更多相关文章
- JVM学习之JVM1.6 GC详解
转自:http://www.cnblogs.com/ggjucheng/p/3977384.html,多谢分享 前言 JVM GC是JVM的内存回收算法,调整JVM GC(Garbage Colle ...
- GC详解及Minor GC和Full GC触发条件
GC,即就是Java垃圾回收机制.目前主流的JVM(HotSpot)采用的是分代收集算法.与C++不同的是,Java采用的是类似于树形结构的可达性分析法来判断对象是否还存在引用.即:从gcroot开始 ...
- GC详解
GC,即就是Java垃圾回收机制.目前主流的JVM(HotSpot)采用的是分代收集算法.与C++不同的是,Java采用的是类似于树形结构的可达性分析法来判断对象是否还存在引用.即:从gcroot开始 ...
- PHP新的垃圾回收机制:Zend GC详解
概述 在5.2及更早版本的PHP中,没有专门的垃圾回收器GC(Garbage Collection),引擎在判断一个变量空间是否能够被释放的时候是依据这个变量的zval的refcount的值,如果re ...
- jvm内存GC详解
一.相关概念 a. 基本回收算法 1. 引用计数(Reference Counting) 比较古老的回收算法.原理是此对象有一个引用,即增加一个计数,删除一个引用则减少一个计数.垃圾回收时,只用收 ...
- GC详解及Minor GC和Full GC触发条件总结
GC,即就是Java垃圾回收机制.目前主流的JVM(HotSpot)采用的是分代收集算法.与C++不同的是,Java采用的是类似于树形结构的可达性分析法来判断对象是否还存在引用.即:从gcroot开始 ...
- JVM&GC详解
1.JVM简介 JVM是java的核心和基础,在java编译器和os平台之间的虚拟处理器.它是一种利用软件方法实现的抽象的计算机基于下层的操作系统和硬件平台,可以在上面执行java的字节码程序. ja ...
- 详解Java GC的工作原理+Minor GC、FullGC
详解Java GC的工作原理+Minor GC.FullGC 引用地址:http://www.blogjava.net/ldwblog/archive/2013/07/24/401919.html J ...
- JAVA中的GC机制详解
优秀Java程序员必须了解的GC工作原理 一个优秀的Java程序员必须了解GC的工作原理.如何优化GC的性能.如何与GC进行有限的交互,因为有一些应用程序对性能要求较高,例如嵌入式系统.实时系统等,只 ...
随机推荐
- Linux 路线 推荐
1.<Linux程序设计>- 靠它来入门,然后装一个linux体系,练习shell(party)和linuxC,把基础打牢: 2. <深入理解Linux内核>和<Linu ...
- C#基础——全局静态类中的静态类变量的设置
前言 今天在设计一个系统用户管理界面的时候,出现了一个问题: 由于要在不同窗体之间传递数据,所以想到了要设置全局变量,比如一个用户有属性,ID,UserName,UserPwd和UserPower,为 ...
- java jar包收集
activation~与javaMail有关的jar包,使用javaMail时应与mail.jar (mail.jar和activation.jar)一起加入到lib中去,具体负责mail的数据源和类 ...
- MyBaits使用小结
Mybatis用like进行模糊查询的时候,配置与所用的数据库有关系,总结了下,具体如下: 1.MySQL :LIKE CONCAT('%',#{empname},'%' ) 或者 LIKE CO ...
- LintCode Minimum Path Sum
Given a m x n grid filled with non-negative numbers, find a path from top left to bottom right which ...
- Jquery 点击图片在弹出层显示大图
http://blog.csdn.net/wongwaidah/article/details/28432427(案例链接出处,本人只是转载收藏) <html> <head> ...
- led驱动
驱动步骤: 1.驱动框架:一般读驱动代码需要module_init一层层找代码 2.硬件配置 代码中led_ioctl函数设置引脚的电平高低,该函数是驱动程序对设备的通道进行统一设置/控制的函数 一. ...
- 使用gnucash查看任意时间段内的所有者权益变动表
gnucash默认会以当年的会计账期显示所有者权益变动表 如果要看指定时间的所有者权益变动表,需要这样做 打开所有者权益变动表 点击上面的[选项] 如图 在常规中自行选择日期 确定后就能够看到指定时间 ...
- HDU1532 网络流:最大流之福德福克森算法
问题描述:约翰是个农民,每次下雨的时候他的庄家总是会被淹没,这就意味着当庄家被水淹后需要很长时间才能重新生长出来,因此,约翰已经建立了一系列排水管道为了使他的庄家尽可能被淹没的最少,也就是说管道的排水 ...
- Spring使用ThreadLocal技术来处理这些问题
过去我习惯于从左到右的思考,因为这符合书写的习惯,对于“好”得前端工程师,我们首先可能会去思考什么是好,好的定义和范围,标准和要求?但现在我习惯于从右到左的思考,因为我觉得越是抽象越难以定义,从粒度更 ...