写在前面的话:本文是作者在阅读了文章底部的相关网站链接后,整理得出的学习资料,并非完全原创,切勿私自拷贝用作商业用途,欢迎大家留言进行学术讨论。如有侵犯到他人权利,请联系本人进行删除,谢谢合作!
7.Java中的分代垃圾回收策略
(1)分代GC的理论基础
分代的垃圾回收策略,基于:不同的对象的生命周期是不一样的。因此,不用生命周期的对象可以采取不用的收集方式,以便提升回收效率
(2)代际划分
-----------------------------------------------------------------------
| Eden | Survivor1 | Survivor2 | Tenured | Permanent |
-----------------------------------------------------------------------
|-------------------------堆内存---------------------|--非堆内存------|
|----------------年轻代------------- -|----年老代----|
Survivor1 和 Suivivor2 的大小是对等的。
非堆内存(持久代),主要用于存储一些类的元数据,常量池,java类,静态文件等信息。对垃圾回收没有显著影响。
(3)年轻代的垃圾回收
Survivo Ratio
|
|
--------------------------------------------------------------------------------
| ------------------------------ | | |
| | newObject(init Obj Alloc) | Eden Space | From Space | To Space |
| ------------------------------ | | |
--------------------------------------------------------------------------------
Young Generation |
|
-------------------------------------------------------
|
-------------------------------------------------------------------------------
| |
| Tenured Space |
| |
-------------------------------------------------------------------------------
Old Generation
-------------------------------------------------------------------------------
| |
| Permanent Space |
| |
-------------------------------------------------------------------------------
Permanent Space
所有新生成的对象都是放在年轻代的。年轻代中的目标就是使生命期短的对象尽快被收集掉。
大部分对象在Eden区中生成,当Eden区满了之后,还存活的对象将被复制到Survivor区中(两个suivivor随机一个)
当这个suivivor区满了之后,此区的对象将被复制到另一个survivor区。
当2个suivivor区都满了之后,从第一个suivivor区复制过来并且还存活的对象将被复制到年老代。
2个Survivor是对称的没有前后关系,总有一个是空的,并且survivor可以配置多个。
(4)年老代的垃圾回收
在年轻代中经历了N次垃圾回收后仍然存活的对象,就会被放到年老代中。因此,可以认为年老代中存放的都是一些生命周期较长的对象。
(5)持久代的垃圾回收
用于存放静态文件,如今Java类、方法等。持久代对垃圾回收没有显著影响。
8.垃圾回收的类型
(1)Scavenge GC
通常而言,当新对象生成并且在Eden区申请空间失败时,会触发Scavenge GC。对Eden区进行GC,清除非存活对象,同时把还存活的对象移动到survivor区,然后整理suivivor。
这种GC方式是对年轻代的Eden区进行的,并不影响年老代。由于绝大部分新生对象都是由Eden区开始的,并且Eden区的空间不会很大,所以Eden区的GC回频繁进行。
(2)Full GC
对整个堆进行整理,包括年轻代、年老代和持久代。Full GC因为要对整个堆整理,所以速度和显效率相较Scavenge GC要慢,应当尽量减少Full GC的次数。
可能倒是Full GC的原因:1.年老代被写满 2.持久代被写满 3.System.gc()被调用 4.上一次GC之后Heap的各域分配策略动态变化
9.各代适用的垃圾回收器
年轻代可用的GC:串行GC(Serial Copying) 并行回收GC(Parallel Scavenge) 并行GC(ParNew)
年老代可用的GC:串行GC(Serial MSC) 并行GC(Parallel MSC) 并发GC(CMS)
10.不同的垃圾回收器
(1)Serial 收集器
串行收集器并不是只能使用一个CPU进行收集,而是当JVM需要进行垃圾回收的时候,需要中断所有的用户线程,直到它回收结束为止,因此又号称“Stop The World” 的垃圾回收器。
串行回收方式适合低端机器,是Client模式下的默认收集器,对CPU和内存的消耗不高,适合用户交互比较少,后台任务较多的系统。
用户线程1 | | | | |
CPU0 -------------->| |--------------->| |---------------->|
| | | | |
用户线程2 | | | | |
CPU1 -------------->| GC 线程 |--------------->| GC 线程 |---------------->|
|---------------->| |---------------->| |
用户线程3 | 年轻代采取 | | 年老代采取 | |
CPU2 -------------->| 复制算法 |--------------->| 标记-整理算法 |---------------->|
| 暂停所有用户 | | 暂停所有用户 | |
用户线程4 | | | | |
CPU3 -------------->| |--------------->| |---------------->|
| | | | |
**注:图中的 CPU0 - CPU3 并不是真正的CPU,而是用户线程
(2)ParNew收集器
ParNew其实就是多线程版本的Serial收集器,同样存在“Stop The World”的问题,是多CPU模式下的首选回收器(ParNew收集器在单CPU下效率远远小于Serial收集器),是Server模式下的默认收集器。
用户线程1 | GC 线程1 | | | |
CPU0 -------------->|--------------->|--------------->| |---------------->|
| | | | |
用户线程2 | GC 线程2 | | | |
CPU1 -------------->|--------------->|--------------->| GC 线程 |---------------->|
| | |---------------->| |
用户线程3 | GC 线程3 | | 年老代采取 | |
CPU2 -------------->|--------------->|--------------->| 标记-整理算法 |---------------->|
| | | 暂停所有用户 | |
用户线程4 | 年轻代采取 | | | |
CPU3 -------------->| 复制算法 |---------------> | |---------------->|
| 暂停所有用户 | | | |
(3)ParallelScavenge收集器
吞吐量优先的收集器,Parallel Scavenge收集器提供了两个参数用于精确控制吞吐量,分别是控制最大垃圾收集停顿时间的-XX:MaxGCPauseMillis参数以及直接设置吞吐量大小的-XX:GCTimeRatio参数。因此在交互不多的云端,比较适合使用该回收器。
(4)ParallelOld收集器
ParallelOld是年老代并行收集器的一种,使用标记整理算法、是年老代吞吐量优先的一个收集器。
用户线程1 | GC 线程1 | | GC 线程1 | |
CPU0 --------------> |--------------->|--------------->|---------------->|---------------->|
| | | | |
用户线程2 | GC 线程2 | | GC 线程2 | |
CPU1 --------------> |--------------->|--------------->|---------------->|---------------->|
| | | | |
用户线程3 | GC 线程3 | | GC 线程3 | |
CPU2 --------------> |--------------->|--------------->|---------------->|---------------->|
| | | | |
用户线程4 | GC 线程4 | | GC 线程4 | |
CPU3 --------------> |--------------->|--------------->|---------------->|---------------->|
| | | | |
(5)SerialOld收集器
SerialOld是年老代Client模式下的默认收集器,单线程执行;在JDK1.6之前也是ParallelScvenge回收年轻代模式下年老代的默认收集器,同时也是并发收集器CMS回收失败后的备用收集器。
(6)CMS
CMS又称响应时间优先(最短回收停顿)的回收器,使用并发模式回收垃圾,使用标记-清除算法,CMS对CPU是非常敏感的,它的回收线程数=(CPU+3)/4,因此当CPU是2核的实惠,回收线程将占用的CPU资源的50%,而当CPU核心数为4时仅占用25%。
用户线程1 | | 用户线程1 | 重新标记 | 用户线程1 | 用户线程1
CPU0 -------------->| |---------------> |---------------->|---------------->|---------------->
| | | | |
用户线程2 | | 用户线程2 | 重新标记 | 用户线程2 | 用户线程2
CPU1 -------------->| 初始标记 |--------------->|---------------->|---------------->|---------------->
|--------------->| | | |
用户线程3 | | 并发标记 | 重新标记 | 并发标记 | 重置线程
CPU2 -------------->| |--------------->|---------------->|---------------->|--------->|----->
| | | | |
用户线程4 | | 用户线程4 | 重新标记 | 用户线程3 | 用户线程3
CPU3 -------------->| |--------------->|---------------->|----------------> |---------------->
| | | | |
CMS模式主要分为4个过程
(1)初始标记<CMS initial mark>
在此阶段,需要中端所有的用户线程
(2)并发标记<CMS concurrent mark>
用户线程和标记线程并发执行,随着内存引用关系的变化,可能会发生原来标记的对象被释放,进而引发新的垃圾,因此可能会产生一系列的浮动垃圾,不能被回收。
(3)重新标记<CMS remark>
(4)并发清除<CMS concurrent sweep>
9.Minor GC vs. Major GC vs. Full GC
Minor GC:年轻代的垃圾回收,只针对于 Eden区以及2个大小相等无先后顺序的survivor区,会执行“Stop The World”机制
Major GC:年老代的垃圾回收,针对于年老代
Full GC:针对于整个空间的垃圾回收,包括年轻代和年老代
相关参考网站:
http://blog.csdn.net/achuo/article/details/45250077
http://jbutton.iteye.com/blog/1569746
7.Java中的分代垃圾回收策略
(1)分代GC的理论基础
分代的垃圾回收策略,基于:不同的对象的生命周期是不一样的。因此,不用生命周期的对象可以采取不用的收集方式,以便提升回收效率
(2)代际划分
-----------------------------------------------------------------------
| Eden | Survivor1 | Survivor2 | Tenured | Permanent |
-----------------------------------------------------------------------
|-------------------------堆内存---------------------|--非堆内存------|
|----------------年轻代------------- -|----年老代----|
Survivor1 和 Suivivor2 的大小是对等的。
非堆内存(持久代),主要用于存储一些类的元数据,常量池,java类,静态文件等信息。对垃圾回收没有显著影响。
(3)年轻代的垃圾回收
Survivo Ratio
|
|
--------------------------------------------------------------------------------
| ------------------------------ | | |
| | newObject(init Obj Alloc) | Eden Space | From Space | To Space |
| ------------------------------ | | |
--------------------------------------------------------------------------------
Young Generation |
|
-------------------------------------------------------
|
-------------------------------------------------------------------------------
| |
| Tenured Space |
| |
-------------------------------------------------------------------------------
Old Generation
-------------------------------------------------------------------------------
| |
| Permanent Space |
| |
-------------------------------------------------------------------------------
Permanent Space
所有新生成的对象都是放在年轻代的。年轻代中的目标就是使生命期短的对象尽快被收集掉。
大部分对象在Eden区中生成,当Eden区满了之后,还存活的对象将被复制到Survivor区中(两个suivivor随机一个)
当这个suivivor区满了之后,此区的对象将被复制到另一个survivor区。
当2个suivivor区都满了之后,从第一个suivivor区复制过来并且还存活的对象将被复制到年老代。
2个Survivor是对称的没有前后关系,总有一个是空的,并且survivor可以配置多个。
(4)年老代的垃圾回收
在年轻代中经历了N次垃圾回收后仍然存活的对象,就会被放到年老代中。因此,可以认为年老代中存放的都是一些生命周期较长的对象。
(5)持久代的垃圾回收
用于存放静态文件,如今Java类、方法等。持久代对垃圾回收没有显著影响。
8.垃圾回收的类型
(1)Scavenge GC
通常而言,当新对象生成并且在Eden区申请空间失败时,会触发Scavenge GC。对Eden区进行GC,清除非存活对象,同时把还存活的对象移动到survivor区,然后整理suivivor。
这种GC方式是对年轻代的Eden区进行的,并不影响年老代。由于绝大部分新生对象都是由Eden区开始的,并且Eden区的空间不会很大,所以Eden区的GC回频繁进行。
(2)Full GC
对整个堆进行整理,包括年轻代、年老代和持久代。Full GC因为要对整个堆整理,所以速度和显效率相较Scavenge GC要慢,应当尽量减少Full GC的次数。
可能倒是Full GC的原因:1.年老代被写满 2.持久代被写满 3.System.gc()被调用 4.上一次GC之后Heap的各域分配策略动态变化
9.各代适用的垃圾回收器
年轻代可用的GC:串行GC(Serial Copying) 并行回收GC(Parallel Scavenge) 并行GC(ParNew)
年老代可用的GC:串行GC(Serial MSC) 并行GC(Parallel MSC) 并发GC(CMS)
10.不同的垃圾回收器
(1)Serial 收集器
串行收集器并不是只能使用一个CPU进行收集,而是当JVM需要进行垃圾回收的时候,需要中断所有的用户线程,直到它回收结束为止,因此又号称“Stop The World” 的垃圾回收器。
串行回收方式适合低端机器,是Client模式下的默认收集器,对CPU和内存的消耗不高,适合用户交互比较少,后台任务较多的系统。
用户线程1 | | | | |
CPU0 -------------->| |--------------->| |---------------->|
| | | | |
用户线程2 | | | | |
CPU1 -------------->| GC 线程 |--------------->| GC 线程 |---------------->|
|---------------->| |---------------->| |
用户线程3 | 年轻代采取 | | 年老代采取 | |
CPU2 -------------->| 复制算法 |--------------->| 标记-整理算法 |---------------->|
| 暂停所有用户 | | 暂停所有用户 | |
用户线程4 | | | | |
CPU3 -------------->| |--------------->| |---------------->|
| | | | |
**注:图中的 CPU0 - CPU3 并不是真正的CPU,而是用户线程
(2)ParNew收集器
ParNew其实就是多线程版本的Serial收集器,同样存在“Stop The World”的问题,是多CPU模式下的首选回收器(ParNew收集器在单CPU下效率远远小于Serial收集器),是Server模式下的默认收集器。
用户线程1 | GC 线程1 | | | |
CPU0 -------------->|--------------->|--------------->| |---------------->|
| | | | |
用户线程2 | GC 线程2 | | | |
CPU1 -------------->|--------------->|--------------->| GC 线程 |---------------->|
| | |---------------->| |
用户线程3 | GC 线程3 | | 年老代采取 | |
CPU2 -------------->|--------------->|--------------->| 标记-整理算法 |---------------->|
| | | 暂停所有用户 | |
用户线程4 | 年轻代采取 | | | |
CPU3 -------------->| 复制算法 |---------------> | |---------------->|
| 暂停所有用户 | | | |
(3)ParallelScavenge收集器
吞吐量优先的收集器,Parallel Scavenge收集器提供了两个参数用于精确控制吞吐量,分别是控制最大垃圾收集停顿时间的-XX:MaxGCPauseMillis参数以及直接设置吞吐量大小的-XX:GCTimeRatio参数。因此在交互不多的云端,比较适合使用该回收器。
(4)ParallelOld收集器
ParallelOld是年老代并行收集器的一种,使用标记整理算法、是年老代吞吐量优先的一个收集器。
用户线程1 | GC 线程1 | | GC 线程1 | |
CPU0 --------------> |--------------->|--------------->|---------------->|---------------->|
| | | | |
用户线程2 | GC 线程2 | | GC 线程2 | |
CPU1 --------------> |--------------->|--------------->|---------------->|---------------->|
| | | | |
用户线程3 | GC 线程3 | | GC 线程3 | |
CPU2 --------------> |--------------->|--------------->|---------------->|---------------->|
| | | | |
用户线程4 | GC 线程4 | | GC 线程4 | |
CPU3 --------------> |--------------->|--------------->|---------------->|---------------->|
| | | | |
(5)SerialOld收集器
SerialOld是年老代Client模式下的默认收集器,单线程执行;在JDK1.6之前也是ParallelScvenge回收年轻代模式下年老代的默认收集器,同时也是并发收集器CMS回收失败后的备用收集器。
(6)CMS
CMS又称响应时间优先(最短回收停顿)的回收器,使用并发模式回收垃圾,使用标记-清除算法,CMS对CPU是非常敏感的,它的回收线程数=(CPU+3)/4,因此当CPU是2核的实惠,回收线程将占用的CPU资源的50%,而当CPU核心数为4时仅占用25%。
用户线程1 | | 用户线程1 | 重新标记 | 用户线程1 | 用户线程1
CPU0 -------------->| |---------------> |---------------->|---------------->|---------------->
| | | | |
用户线程2 | | 用户线程2 | 重新标记 | 用户线程2 | 用户线程2
CPU1 -------------->| 初始标记 |--------------->|---------------->|---------------->|---------------->
|--------------->| | | |
用户线程3 | | 并发标记 | 重新标记 | 并发标记 | 重置线程
CPU2 -------------->| |--------------->|---------------->|---------------->|--------->|----->
| | | | |
用户线程4 | | 用户线程4 | 重新标记 | 用户线程3 | 用户线程3
CPU3 -------------->| |--------------->|---------------->|----------------> |---------------->
| | | | |
CMS模式主要分为4个过程
(1)初始标记<CMS initial mark>
在此阶段,需要中端所有的用户线程
(2)并发标记<CMS concurrent mark>
用户线程和标记线程并发执行,随着内存引用关系的变化,可能会发生原来标记的对象被释放,进而引发新的垃圾,因此可能会产生一系列的浮动垃圾,不能被回收。
(3)重新标记<CMS remark>
(4)并发清除<CMS concurrent sweep>
9.Minor GC vs. Major GC vs. Full GC
Minor GC:年轻代的垃圾回收,只针对于 Eden区以及2个大小相等无先后顺序的survivor区,会执行“Stop The World”机制
Major GC:年老代的垃圾回收,针对于年老代
Full GC:针对于整个空间的垃圾回收,包括年轻代和年老代
相关参考网站:
http://blog.csdn.net/achuo/article/details/45250077
http://jbutton.iteye.com/blog/1569746