您的位置:首页 > 其它

JVM 垃圾回收原理

2013-10-09 20:44 225 查看
JVM的自动垃圾收集(Garbage Collection)使得开发人员无需关注垃圾收集的细节,不过,当内存问题成为系统瓶颈的时候,我们就需要了解一下JVM的垃圾收集机制了。

应用程序中生成的对象绝大部分都是临时对象,属于那种生的快死的快的,来也匆匆,去也匆匆,当然也有伴随应用程序的生命周期而存在的对象,鉴于对象的生命周期的不同,JVM的内存是分代(Generation)管理的。如果把JVM看作一个战场,把各个对象看作士兵,那么大部分的士兵刚投入战场不久就英勇就义,只有少部分的士兵能够在战场中摸爬滚打能够坚持一段时间。(史上最残忍的战场,阿弥陀佛,善哉!善哉!)。分代情况如下图所示:



其中,年轻代(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:

serial collector:针对young generation的串行垃圾收集器,使用stop-the-world(就是暂停整个应用程序的执行)的形式,利用单线程通过复制live objects到survivor space或tenured generation的方法来进行垃圾收集。

parallel scavenge collector:针对young generation的并行垃圾收集器,利用多个GC线程来进行垃圾收集,每个线程的GC方法和serial collector一样。

parallel new collector:针对young generation的增强的并行垃圾收集器,以便可以和CMS一起使用。

serial old collector:针对tenured generation的串行垃圾收集器,使用stop-the-world形式,利用单线程通过mark-sweep-compact的方法进行垃圾收集。

parallel old collector:针对tenured generation的并行垃圾收集器,利用多线程进行垃圾收集,方法和serial old collector一样。

parallel compacting collector:对于young generation使用和parallel new collector一样的算法,对于tenured generation使用了新的算法(mark-summary-compact),该收集器用来替代parallel new collector和parallel old collector。

concurrent mark-sweep collector:对于young generation使用和parallel new collector一样的算法,对于tenured generation使用跟应用程序并发的方式,收集期间也有引起stop-the-world的暂停Mark阶段,也有伴随着应用程序运行的并发Mark和并发Sweep阶段,降低了应用程序暂停的时间。

可以看出这些垃圾收集器分为3种类型:串行,并行,并发;串行的就是单线程的,并行的就是多线程的,串行并行都是stop-the-world的,而并发是多线程的,但不完全是stop-the-world。

先说这么多,GC本来就是一个内容丰富的课题,关于各垃圾收集器背后的算法,我想通过另一篇文章来讨论一下,毕竟每个算法详细的讲一下都能成为一篇文章,另外关于GC性能的调整也是一个重要的话题,陆续也将总结一下。总结的过程也是一个学习的过程,写这篇文章时也参阅了一些sun的官方内容,同时加上自己的理解,希望能给需要的人一些帮助。当然,我的理解也可能有偏差,如有不当之处,欢迎指正。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: