三大Java 虚拟机垃圾回收机制的比较(HotSpot, JRockit, IBM JVM)

原文地址:http://apmblog.compuware.com/2011/05/11/how-garbage-collection-differs-in-the-three-big-jvms/

========================================================================================

Hotspot JVM 使用和 IBM Websphere OracleWeblogic 不同的垃圾回收机制,但是垃圾回收的概念和算法是相通的。

 

HotSpotJVM

 

1 HotSpotJVM 使用内存分区(如永久 perm 区和分代 Generation Heap 区),分代区 (Generation Heap ) 又包括新生 Yong 老生 Old/Tenured 区, Yong 区中又分为 Eden Survior 区( 2 块);

 

2 Yong GC :对象先在 Yong 区的 Eden 中得到分配,任何时候 Eden 区满了就会触发 Yong Full GC 会把 Yong Eden 中仍存活的 Live 对象拷贝到空的那个 Survior 区,除此之外,另外一个 Survior 区中的对象也会被检查和拷贝(在 2 Survior 区之间拷贝对象的频率是可配置的),其结果就是对象仅存在于一个 Survior 区中,而 Eden 区和 另一块 Survior 区是空的。这种形式的 GC 叫“拷贝收集( Copy Collection )”。 Yong 区中多次 GC 后仍存活的对象会被提升 / 拷贝到 Old 区。

 

3 Old GC :标记和打扫( Mark & Sweep) 算法是老生区 (OldHeap) 使用的 GC 算法,与新生代 Yong 区算法不同的地方在于它不拷贝对象。对象越多 GC 消耗时间越长,因此老生区 GC 代价很高并尽量避免, 因此我们需要保证对象仅仅从 Yong 区拷贝到 Old 区并保证 Old 区不被填满,因此,代区的大小是 Hotspot JVM 中单一的一个最重要的优化参数。如果我们不能阻止对象从 Yong 区拷贝到 Old 区,我们可以使用“并发标记和打扫算法”( CMS -Concurrent Mark and Sweep) ,此算法可以并行的进行收集操作。 (停顿时间:串行 (Serial) < 平行 (Parallel) < 并发 (Concurrent) )。

 

Old GC 还有其他问题,比如“碎片问题”会导致“慢分配”,更长的打扫时间并最终会导致 OOM (当分配大对象而遇到的全是小空间时) .

 

碎片问题可通过 被称为“压缩”的方法来解决。“串行和平行算法( Serialand Parallel) ”会在每次 Old 区进行 GC 时进行压缩,它不对整个 Old 区压缩而只对 Old 区中碎片程度达到一定 Level 的区域区进行。相比之下,“并发标记和打扫算法 CMS ”根本就不会进行压缩。当对象不能再被分配时,一个串行的“主要 MajorGC ”会被触发。

 

因此, HotSpot 的第二个调整参数是选择正确的 GC 策略, GC 策略的选择会影响应用的性能, HotSpot 中的大部分 GC 策略调整选项参数是是关于分片和压缩的, HotspotJVM 没有提供太多调整参数,因此,唯一的方法是优化代码减少申请对象的次数。

 

4) Permanent Generation 永久区: 保存属于类的(静态的)属性和字符串常量等,永久区的 GC 只会发生在“主要 Major GC ”时( Major GC 很少发生),因此很多人认为 Hotspot JVM 在永久区根本不会 GC

 

Major GC - Stops the world and cost much time , e.g. Full GC.

 

OracleJRockit

 

1) Oracle WebLogic 使用的 JVM ,将来会和 Hotspot 合并

 

2) Heap 策略 - 也使用“分代 Heap ”,而且支持一个所谓的“连续 Heap ”。分代 Heap 分为:老生区( Old/Tenured) 和苗圃 / 新生区( Nursery) ,当对象被申请时,他们被放在一个新生区中称为 Keep Area 的地方, GC 时, Keep Area 不会被考虑而其它仍然存活的对象会被马上移到老生区。因此,新生区的大小是 JRockit 很重要的参数。 JRockit 在第二次新生代 GC 时就会拷贝那些对象到 Old 区。

 

JRockit 的“连续 Heap ”不区分“新”和“老”的对象,常常在特定的情况下比如以大吞吐量下的批量任务会产生很好的性能,它是 JRockit Server JVM 模式下的默认设置,而且往往不是正确的选择,因为典型的 Web 应用不是面向吞吐量而是面向响应时间,因此人们往往会选择低停顿时间模式和分代 GC 策略。

 

3) CMS -

大部分的 CMS 标记 阶段可分为 4 个部分

    1. 初始标记 - 标记生成 Live 对象的 Root 集合 - Java Thread 会被 paused

    2 并发标记  - 根据 root 集合中的对象查找并标记其引用的 Live 对象 -- Java Thread 正常运行

    3 预清理 - 找出“并发标记”发现的需要修改的地方并发现和标记其它额外的 Live 对象 -- Java Thread 正常运行     4 最终标记 - 找出在预清理阶段发现的需要改变的地方并发现和标记其它额外的 Live 对象 -- Java Thread 会被 Paused

 

CMS 打扫阶段 也和 Application 并发执行,   但和 Hotspot JVM 的分 2 个阶段相比, JRockit 会先清扫 Heap 的第一半部分, 在此阶段,线程会被允许在 Heap 的第二半部分进行对象申请。在一个短暂的同步停顿后,会打扫第二半部分然后会有一个短暂的最后的停顿期。

因此, JRockit 的算法比 HotSpot 的算法停顿更多,但是标记阶段会短一些。而且它不像 HotSpot JVM 那样可以通过调整未用内存的百分比来触发 GC

 

4) 压缩

JRockit 在所有的 Old 老生区 GC 进行压缩, 包括 CMS 它通过一种按 Heap 中分区增量的模式进行的,这些各类参数可以调整,比如按堆百分比压缩,或 最大多少对象会被压缩,而且你可以完全把压缩关掉 或者在 GC 时进行“完全压缩”。因此可配置性比 HotSpot 更强。

 

5) 线程本地分配 TLA Thread Local Allocation)

JRockit 默认使用线程本地分配 TLA, 这允许线程不需要同步即可分配对象,这将有利于分配速度, TLA 的大小而且可以配置,大的 TLA 可以优化使用大量线程本地分配对象的应用, 另一方面,太大的 TLA 会导致更多的碎片, 因为 TLA 是被线程以排斥的方式独有的,因此受限于线程数并依赖于应用的架构。

 

6) 大对象和小对象

JRockit 在分配大对象和小对象时区别对待, 大小的定义在 JVM 的版本不同而不同,常常 2-128Kb 之间,大对象在线程本地意外的 Old 区分配,而新生 Yong 区使用“拷贝收集 -Copy Collection (见 Hotspot Yong GC )”,在某些点,拷贝一个对象变得比它被 GC 更消耗。

 

7) 没有永久区  -- JRockit JVM 没有永久区 , 所有类的属性和字符串常量放在通常的 Heap 区域, 因此如果它不再被使用,会被马上回收。

 

IBM JVM

 

IBM JVM IBMWebsphere 使用,它和 JRockit 有很多相同地方,它默认的使用一个“连续的 Heap ”, 特别是在 Websphere 安装过程中,这往往是导致最初的低性能的原因。 它和 JRockit 一样区分大小对象,并默认使用线程本地分配 TLA 它也没有“永久区”, 但是 IBM JVM 也支持分代模型并且看起来更像 HotSpot JVM 比如它的分代模型包括 “新生区” “老生区”, 新生区 又分为“分配区( Allocate )” Survior 区”,新对象在 Allocate 区分配并在 GC 时拷贝到 Survior 区,这意味着一个对象在被移动到 Old 区时会被在 2 个区之间多次拷贝 . JRockit 一样, IBM JVM 有多个选项可以配置“压缩”阶段, 可以配置为“关闭”或“每次 GC 都进行压缩”, JRockit 相比,默认的触发条件是由于一系列的触发而不是导致“完全”压缩,而且这个可以被配置选项更改。

 

 

Java 7 会宣称“ G1 - Production Ready ,而且 G1 是不同的。


我来评几句
登录后评论

已发表评论数()

相关站点

+订阅
热门文章