Java垃圾回收器
现在你知道垃圾回收的基础知识,也了解了如何在一个示例项目上观察gc过程。本节会介绍java可用的垃圾收集器和如何在命令行启用他们。
通用堆相关参数
JAVA中有很多命令行开关。这节展示了在本文中常用的开关。
开关 | 描述 |
---|---|
-Xms | 设置初始堆大小 |
-Xmx | 设置最大堆大小 |
-Xmn | 设置年轻代大小 |
-XX:PermSize | 设置持久代初始大小 |
-XX:MaxPermSize | 设置持久代最大大小 |
Serial GC
该GC在JAVA SE 5,6 的客户端风格机器中是默认的GC。采用该GC后,minor / major gc 都是顺序收集的(使用单个虚拟CPU)。除此之外,它还使用一个标记-压缩收集方式(这种方式将老点的内存移动到堆的开始,以便新的内存分配可以在堆的末尾连续分配。)针对内存的压缩使得在堆中分配一段内存更快。
使用场景
该GC适用于那些没有低停顿时间要求的客户端风格应用。它只利用一个虚拟处理器来进行垃圾回收(正如名称所说)。在今天的硬件下,Serial GC能够高效管理一个拥有几百M的堆,(带有一个相对短的最坏停顿时间,full gc大概在几s)。
另外一个常见的场景就是用于有很多JVM实例运行在同一个机器上(某些情况下JVM实例数比可用的CPU核数还多)。在这种场景下,一个JVM只使用一个处理器来进行垃圾回收可以更好的降低对其他JVM的干扰,尽管gc时间会变得更长。这是一个折中的方案。
最后,随着只有很小内存和很少CPU的嵌入式设备的增长,Serial GC 会东山再起。
命令行开关
-XX:+UseSerialGC
Parallel GC
该GC采用多个线程来完成年轻代GC。默认的,主机有n个CPU,会使用n个垃圾回收线程。该线程数可以通过如下参数设置:
-XX:ParallelGCThreads= 线程数
在一个只有单核CPU的机器上会采用默认的垃圾回收器,即使手动指定了Parallel GC,在一个有2个CPU的机器上,该GC通常作为默认的GC,并且当有更多的CPU时,可预期的,会减少年轻代的GC 停顿时间。
使用场景
该GC通常也叫吞吐量优先GC,因为它是用多个CPU来加快应用的吞吐量。该CPU可以用于当有很多工作要做,而且长的停顿是可以接受的场景。比如:打印报告或者账单等批处理操作,或者大量查询数据库的场景。
命令行开关
-XX:+UseParallelGC
打开这个开关,你会得到一个多线程的年轻代垃圾回收器和一个单线程的年老代GC收集器。这个也会堆年老代做单线程的压缩。
-XX:+UseParallelOldGC
打开这个开关后,你会得到一个年轻代 年老代都是多线程回收的垃圾回收器,包括年老代的压缩也是多线程。HotSpot只在年老代做压缩。年轻代被认为是一个copy 收集器,所以不需要压缩。
压缩被描述为移除对象之间的空洞的一系列操作。在一次垃圾回收清扫后,在存活对象间可能会有一些空洞。压缩并移动对象来清除空洞。有的GC可能不是一个压缩型的GC。因此Parallel gc 和 parallel 压缩 gc的区别就是后者在垃圾回收清扫会压缩空间,而前者不会。
CMS gc
Concurrent Mark Sweep (CMS) 也被称为年老代的低停顿时间收集器。它尝试最小化停顿时间,因为大多数GC工作都与应用程序线程并行执行。一般来说,低停顿时间的垃圾回收器不会拷贝或者压缩存活的对象。垃圾回收时并没有移动存活的对象,如果碎片化称为一个问题,那么需要一个更大的堆。
NOTE:CMS 在年轻代的算法与parallel gc 相同。
使用场景
CMS GC 应该被用于那些要求低停顿时间,并且与垃圾收集器共享资源(译注:CPU资源吗?)的应用。比如:桌面UI应用(响应用户操作事件), Web服务器(响应请求)或者数据库(响应查询)。
命令行开关
采用CMS gc:
-XX:+UseConcMarkSweepGC
设置线程数:
-XX:ParallelCMSThreads=n
G1 GC
G1 = Garbage first
在jdk7 开始可用,并作为在长时间内CMS的替代者,G1是一个并行的,并发的,增量压缩的低停顿时间GC,并且内存布局也与前面描述的GC大不相同。这里不会讨论详细的信息。
命令行开关
-XX:+UseG1GC