Java垃圾回收-分代收集

Java自动垃圾回收(Automatic Garbage Collection)是自动回收上不再使用的内存,new的对象在程序中没有引用指向它,就会被回收。回收的实现很多,有Reference Counting Collector/Tracing Collector/Compacting Collector/Coping Collector/Generational Collector/Adaptive Collector。本文记录的是HotSpot Java VM采用的Generational Collector(分代收集器)

为什么分代?

下图是随着时间的推移,经历垃圾回收后存活下的数据大小情况。可以看出大部分对象存活期很短,随着时间的推移越来越少的对象存活下来。因此,可以针对不同的堆内存采取不同的回收频率和方法,以提高JVM性能。

技术分享

内存分代概念

技术分享

Eden:用于new对象时分配的内存空间,大部分初始new的对象位于该空间

Survivor Space:在eden中经历垃圾回收后,存活下来的对象被存储在该空间

tenured Space:在survivor space中存在了一段时间的对象会被挪到该空间

Permanent Space:JVM使用的元数据,如classloader加载的class/method定义(反射后的数据)。

Code Cache:用于编译和存储原代码

Permanent Space和Code Cache不属于generation collector回收范围。

如何分代收集

new对象会最初分配在eden中,当eden满时触发minor garbage collection。

Minor GC(又称作Young GC)针对young generation:

  • eden/S0中存活的对象被复制到S1中,eden/S0被清空
  • 每次minor gc,存活对象的age会加1,当age超过阈值后,对象被存到old generation中。
  • S0和S1是相对的,第一次Minor GC时S0/S1都是空的,从eden往S0复制,第二次minor gc就是从eden/S0往S1复制,下一次是eden/S1到S0,以后依次类推。
Minor GC采用的是复制收集,young generation中的对象大部分是不再使用,所以复制存活下来的对象到新空间,旧空间整体回收,这样的一个过程会更快。

随着Minor GC的发生,被promoted到old generation的对象越来越多,当old generation满时就触发了major garbage collection。Major GC(又称作Old GC)针对old generation,采取marking-deletion-compact(标记-清除-压缩内存)的方法。(补:压缩内存,就是把活着的对象放在一块,省出连续的空闲内存,便于分配)

通常Major GC又被认为是Full GC,因为Major GC发生时会伴随着Minor GC:一次Minor GC将存活对象放到old generation时导致old generation满了,从而导致Major GC。这一段时间整个堆内存表现出的现象是都进行了garbage collection。

建议

Minor/Major GC都是Stop the World事件,应用程序会停止执行,直到GC完成。Major GC发生时,整个堆内存都受到了影响,持续时间长。

所以应该尽量避免或减少Major GC(减少被放到old generation的对象);尽量最大化堆内存。

实际使用

启动java程序时通过设置相关命令参数调节垃圾回收的方法、阈值或频率来优化GC对程序的影响,常用命令如下:

    Switch Description
    -Xms Sets the initial heap size for when the JVM starts.
    -Xmx Sets the maximum heap size.
    -Xmn Sets the size of the Young Generation.
    -XX:PermSize Sets the starting size of the Permanent Generation.
    -XX:MaxPermSize Sets the maximum size of the Permanent Generation
GC的串并行

串行GC在JavaSE 5/6上是默认方式,常用于对暂停时间要求不高、客户端类型的应用程序上,也适用于应用程序的数目比CPU多的情况,这样GC时JVM之间的影响小。MB级别的堆内存进行Full GC时只需要几秒。设置的命令是-XX:+UseSerialGC。

并行GC使用多线程进行Minor GC,线程数默认与CPU数相等。设置的相关命令是-XX:+UseParallelGC和-XX:ParallelGCThreads=<desired number>(指定线程数)。-XX:+UseParallelOldGC会设置Minor GC和Major GC都采用多线程。

CMS

并发标记清除收集器(Concurrent Mark Sweep)用于old generation的垃圾回收,它尽力减少程序的暂停时间,GC工作和应用程序的线程并发执行。它不做compact(压缩)堆内存,省去了内存的拷贝和移动。当内存碎片过多无法满足分配时,就直接重新分配一块更大的堆内存。CMS适用于webserver或者查询类的应用

相关命令:-XX:+UseConcMarkSweepGC和-XX:ParallelCMSThreads=<n>(设置并行线程数)

G1 Garbage Collector

G1回收器在Java7中被引进,希望能取代CMS,它主要是并发、增量式的compact内存,以取得低暂停。相关命令:-XX:+UseG1GC

一个实例

java -Xmx12m -Xms3m -Xmn1m -XX:PermSize=20m -XX:MaxPermSize=20m -XX:+UseParallelOldGC -jar Java2demo.jar

参考:http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/gc01/index.html

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。