JVM的自动垃圾收集(Garbage Collection)使得开发人员无需关注垃圾收集的细节,不过,当内存问题成为系统瓶颈的时候,我们就需要了解一下JVM的垃圾收集机制了。
应用程序中生成的对象绝大部分都是临时对象,属于那种生的快死的快的,来也匆匆,去也匆匆,当然也有伴随应用程序的生命周期而存在的对象,鉴于对象的生命周期的不同,JVM的内存是分代(Generation)管理的。如果把JVM看作一个战场,把各个对象看作士兵,那么大部分的士兵刚投入战场不久就英勇就义,只有少部分的士兵能够在战场中摸爬滚打能够坚持一段时间。(史上最残忍的战场,阿弥陀佛,善哉!善哉!)。分代情况如下图所示:

default arrangement of generations
其中,年轻代(Young Generation)包含伊甸园(Eden)和2段幸存者空间(Survivor Spaces),伊甸园当然是新生对象的乐园(只在乎曾经拥有,不在乎天长地久。也许看作前线战场更为合适:)(也有部分大对象直接分配在年老代)。而幸存者空间是用来保存上次GC之后依然存活的对象,经过战事的洗礼,能够存活下来实属不易,说明你是一个优秀的士兵,特此晋升一下,并且分配给你一间前线作战指挥所。2段空间保持其中一个为空,后面再详细说明缘由和作用。
年老代(Tunured Generation)中存放的是那些从幸存者空间经过多次GC依然存活的对象,他们是由年轻的军官经过许多战事的磨砺而来,已经成为老一辈的无产阶级革命家。
永久代(Permanent Generation)是保存VM描述对象的数据,比如类定义,方法定义的信息。这里属于战争的大后方。
当一个对象不再被引用时,该对象就是一个不可达的对象,dead的了,战死沙场了,就成为garbage了(汗一个)。GC就是通过一定的算法,判断一个对象可达与否,通常是遍历所有可达的对象,剩下的对象就是认为是garbage,然后销毁这些garbage,释放内存。
既然内存是分代管理的,GC也就自然而然是分代收集的。
由于年轻代进进出出的人多而频繁,所以年轻代的GC也就频繁一点,但涉及范围也就年轻代这点弹丸之地内的对象,其特点就是少量,多次,但快速,称之为minor collection。当年轻代的内存使用达到一定的阀值时,minor collection就被触发,Eden及某一Survior space(from space)之内存活的的对象被移到另一个空的Survior space(to space)中,然后from space和to space角色对调。当一个对象在两个survivor space之间移动过一定次数(达到预设的阀值)时,它就足够old了,够资格呆在年老代了。当然,如果survivor space比较小不足以容下所有live objects时,部分live objects也会直接晋升到年老代。
Survior spaces可以看作是Eden和年老代之间的缓冲,通过该缓冲可以检验一个对象生命周期是否足够的长,因为某些对象虽然逃过了一次minor collection,并不能说明其生命周期足够长,说不定在下一次minor collection之前就挂了。给一个士兵晋升是要有一定的考察期的:)。这样一定程度上确保了进入年老代的对象是货真价实的,减少了年老代空间使用的增长速度,也就降低年老代GC的频率。
当年老代或者永久代的内存使用达到一定阀值时,一次基于所有代的GC就触发了,其特定是涉及范围广(量大),耗费的时间相对较长(较慢),但是频率比较低(次数少),称之为major collection(full collection)。通常,首先使用针对年轻代的GC算法进行年轻代的GC,然后使用针对年老代的GC算法对年老代和永久代进行GC。
常用的garbage collectors:
可以看出这些垃圾收集器分为3种类型:串行,并行,并发;串行的就是单线程的,并行的就是多线程的,串行并行都是stop-the-world的,而并发是多线程的,但不完全是stop-the-world。
先说这么多,GC本来就是一个内容丰富的课题,关于各垃圾收集器背后的算法,我想通过另一篇文章来讨论一下,毕竟每个算法详细的讲一下都能成为一篇文章,另外关于GC性能的调整也是一个重要的话题,陆续也将总结一下。总结的过程也是一个学习的过程,写这篇文章时也参阅了一些sun的官方内容,同时加上自己的理解,希望能给需要的人一些帮助。当然,我的理解也可能有偏差,如有不当之处,欢迎指正。
本日志由 flyinweb 于 2010-01-11 15:03:04 发表,目前已经被浏览 4212 次,评论 0 次;
作者添加了以下标签: JVM,Garbage Collection,GC;
引用通告:http://www.517sou.net/Article/383/Trackback.ashx
It is quite useful and interesting too.
VIRT 的上限是64G,也就是36位, cat /proc/cpuinfo的结果是:addre
昨天要准备用线程重写webbench,试验了下Fedora Linux 2.6.35.14
不明白您的具体的意思是什么?
已经发送到你QQ邮箱
http://www.2mysite.net/scriptencoder/screnc.asp 站长你好,看
你好,我发现一个问题,就是从mysqld2同步过来的数据,在mysqld1的
晕,我说是怎么回事情,原来我和你一样,忘记设置了活动分区