垃圾收集器(Garbage Collection,GC)
作用:排查内存泄漏、内存溢出问题;高并发量瓶颈时,进行监控、调节
1.垃圾收集算法
a.标记-清除算法首先标记所有要回收的对象,然后统一回收。
存在.效率问题,标记和清除两个过程的效率都不高; 空间碎片问题,标记清除后会产生大量不连续的内存碎片,空间碎片太多可能会导致以后在程序运行中需要分配较大对象时,无法找到足够的连续内存而不得不提前触发另一个垃圾回收动作。
b.复制算法
两个区域A和B,初始对象在A,继续存活的对象被转移到B。此为新生代最常用的算法。
缺点:将内存缩小为了原来的一半,对内存空间耗费较大。在对象存活率较高时,需要进行多次复制操作,效率会变低。
c.标记-整理算法
标记可回收对象,所有存活对象向一端移动,然后清理掉端边界以外的对象
d.分代收集算法
根据对象存活周期的不同将内存分为几块,根据各年代特点选择合适的收集算法。一般分为新生代和老年代
在新生代采用复制算法,在老年代采用“标记-清除”或者“标记-整理”算法。
JVM将整个堆划分为Young区、Old区和Perm区,分别存放不同年龄的对象。
-Xms:堆起始大小
-Xmn:堆的最大大小,通常-Xms,-Xmn:设为一样大,避免后期的堆收缩
-XX:SurvivorRatio:新生代中Eden区域与Survivor区域的容量比值,默认为8:1
-XX:PretenureSizeThreshold:新生代直接晋升到老年代的对象大小,大于这个参数的对象将直接在老年代分配
-XX:MaxTenuringThreshold:晋升到老年代的年龄。一个对象坚持过一次Minor GC后,年龄就增加1,当超过阀值就进入老年代。默认15.
Young区分为Eden区和两个相同大小的Survivor区,其中所有新创建的对象都分配在Eden区域中,当Eden区域满后会触发minor GC 将Eden区仍然存活的对象复制到其中一个Survivor区域中,另外一个Survivor区中的存活对象也复制到这个Survivor区域中,并始终保持一个Survivor区时空的。
Old区存放 Young区Survivor满后触发minor GC后仍然存活的对象。当Eden区满后会将存活的对象放入Survivor区域,如果Survivor区存不下这些对象,GC收集器就会将这些对象直接存放到Old区中,如果Survivor区中的对象足够老,也直接存放到Old区中。如果Old区满了,将会触发Full GC回收整个堆内存。
Perm区主要存放类的Class对象和常量,如果类不停地动态加载,也会导致Perm区满。Perm区地垃圾回收也是有Full GC触发地。
新创建的对象被分配在新生代,如果对象经过几次回收后仍然存活,那么就把这个对象划分到老年代。老年代的收集频度不象年轻代那么频繁,这样就减少了每次垃圾回收所需要扫描的对象,从而提高了垃圾回收效率。
新生代,复制算法;老年代,标记清除或标记整理算法
PS:
两个概念:新生代和年老代,来自Heap
新生代:初始对象,生命周期短的
永久代:长时间存在的对象
2.垃圾收集器
a. serial 收集器(JDK 1.3)
单线程的收集器。进行垃圾收集时,必须暂停其他所有的工作线程,直到它收集结束。
新生代收集器。
b. ParNew 收集器
serial 收集器的多线程版本。
新生代收集器。
c. Parallel Scavenge 收集器
新生代收集器,使用复制算法的收集器。
并行的多线程收集器。
目标是达到一个可控制的吞吐量(运行用户代码的时间与CPU总消耗时间的比值,CPU总消耗时间=运行用户代码时间+垃圾收集时间)
吞吐量优先
JDK 1.4
d. Serial Old 收集器
Serial 收集器的老年代版本。
单线程收集器。
“标记-整理”算法
在JDK 1.5以及之前的版本中,与Parallel Scavenge 搭配使用。
CMS收集器的后备预案。
e. Parallel Old 收集器
Parallel Scavenge 的老年代版本。
JDK 1.6 提供
f. CMS 收集器(Concurrent Mark Sweep)
"标记-清除"算法老年代
JDK 1.5 中发布。
第一次出现在JDK 6u14中,JDK7u4中成为成熟商用版本。
- 并发与并行。
- 分代收集。
- 空间整合。
- 可预测的停顿。

连线的是可以相互搭配使用。横线上半部分是新生代,下半部分是老年代。

并行(Parallel):多条垃圾收集线程并行工作,但此用户线程仍处于等待状态。
并发(Concurrent):用户线程与垃圾收集线程同时执行(并不一定是并行的,可能会交替执行),用户程序在继续运行,而垃圾收集程序运行在另一个CPU上。