[置顶] java虚拟机之垃圾收集器、内存分配与回收策略、GC都干了些什么

JDK1.7 Update14 之后 HotSpot虚拟机,两个虚拟机之间有 连线的说明可以 搭配使用
[置顶] java虚拟机之垃圾收集器、内存分配与回收策略、GC都干了些什么_第1张图片


收集器 新生代 or 老年代 单线程 or 多线程 目标 特点 联系 or 适用
Serial收集器 新生代 单线程  
1.是最基本、发展历史最悠久的收集器
2.老而无用、食之无味弃之可惜

是虚拟机运行在Client模式下的默认新生代收集器
ParNew收集器 新生代 多线程 使用多线程进行垃圾收集
1.和Serial差不多,是Serial的多线程版本
2.默认开启的收集线程数与CPU的数量相同

1.是许多运行在Server模式下的虚拟机中首选的新生代收集器
2. 只有它能和CMS收集器配合工作
Parallel Scavenge收集器 新生代 多线程 达到一个可控制的吞吐量(运行用户代码时间/全部时间),高效的利用CPU 具有GC自适应的调节策略(虚拟机根据当前系统的运行情况收集性能监控信息,动态调整参数以提供最合适的停顿时间或者最大的吞吐量  
Serial Old收集器 老年代 单线程 给Client模式下的虚拟机使用  
在Server模式下:
1.在jdk1.5以及之前的版本中与Parallel Scavenge收集器搭配使用
2.作为CMS收集器的后备预案,在并发收集发生Concurrent Mode Failure时使用
Parallel Old收集器 老年代 多线程 解除了 Parallel Scavenge只能和Serial Old搭配(Serial Old收集器在服务端应用的拖累) 是 ParallelScavenge收集器的老年代版本  在注重吞吐量以及CPU资源敏感的场合,都可以优先考虑Parallel Scavenge 加Parallel Old收集器
CMS(Concurrent Mark Sweep)收集器 老年代   一种以获得最短回收停顿时间为目标的收集器. 整个过程分为4个步骤 B/S--重视服务的响应速度,希望停顿时间最短
G1收集器     在未来可以替换掉CMS
1.并行与并发
2.分代收集
3.空间整合
4.可预测的停顿-建立可预测停顿时间模型
面向服务端应用的垃圾收集器




1.CMS(Concurrent Mark Sweep)收集器,并发收集,低停顿
      步骤:
          ①初始标记--单线程,停顿
          ②并发标记--单线程,并发     
          ③重新标记--多线程,并行,停顿
          ④并发清除--单线程,并发
          ①③两个步骤仍然需要stop the world
      缺点:
          ①CMS收集器对CPU资源非常敏感
          ②CMS收集器无法处理浮动垃圾,可能出现“Concurrent Mode Failure”失败而导致另一次 Full GC 产生。由于CMS并发清理阶段用户线程还在运行着,伴随程序运行自然就还会有新的垃圾不断产生;要是CMS运行期间预留的内存无法满足程序要求,就会出现一次Concurrent Mode Failure 失败,这时启用SerialOld 收集器来重新进行老年代的垃圾收集,这样停顿的时间就很长了。
          ③CMS时一块基于“标记-清除”算法实现的收集器,当无法找到足够大的连续空间来分配当前对象,不得不提前触发一次Full GC 

 

2.G1收集器
     对于空间整合:G1从整体上看是基于“标记-整理”算法实现的收集器,从局部(两个Region之间)上来看是基于“复制”算法实现的,这意味着 G1运作期间不会产生内存空间碎片,收集后能提供规整的可用内存
     G1收集器将整个java堆划分为多个大小相等的独立区域,虽然还保留新生代和老年代的概念,但新生代和老年代不再是物理隔离了,他们都是一部分Region(不需要连续)的集合
     
     G1跟踪各个Region里面的垃圾堆积的价值大小(回收所获得空间的阿晓以及回收所需时间的经验值),在后台维护一个优先列表,每次根据允许的收集时间,优先回收价值最大的Region(Garbage-First名称的来由)。这种使用Region划分内存空间以及有优先级的区域回收方式,保证了G1收集器在优先的时间内可以获取尽可能高的收集效率
 
     Region并不是孤立的,如何做到判定对象是否存活的时候而不用扫描整个java堆?
          Region之间的对象引用以及其他收集器中的新生代与老年代之间的对象引用,在虚拟机都是使用Remembered Set来避免全堆扫描的。G1中每个Region都有一个与之对应的Remembered Set,虚拟机发现程序在堆Reference类型的数据进行写操作时,会产生一个Write Barrier 暂时中断写操作,检查 Reference引用的对象是否处于不同的Region之中,如果是,便通过 CardTable把相关引用信息记录到被引用对象所属的Region的Remembered Set之中。当进行内存回收时,在GC根节点的枚举范围中加入 Remembered Set 即可保证不对全堆扫描也不会有遗漏

     G1收集器的步骤:
          ①初始标记--单线程、停顿--标记GC Roots能直接关联到的对象
          ②并发标记--可达性扥洗,并发--从GC Root开始对堆中对象进行可达性分析,找出存活的对象
          ③最终标记--并行 ,停顿--为了修正在并发标记期间因用户程序继续运作而导致标记产生变动的那一部分标记记录,阻尼及将这段时间对象变化记录在线程Remembered Set Logs里面,最终标记阶段需要把Remembered Set Logs的数据合并到 Remembered Set 中
          ⑥筛选回收-并行,停顿




内存分配与回收策略

新生代GC(Minor GC):指发生在新生代的来及收集动作,一般minor gc 非常频繁,回收速度也比较快
老年代GC(Major GC/Full GC):指发生在老年代的GC,出现了Major GC,经常会伴随至少一次的Minor GC。


内存分配策略:

1.对象优先在 Eden 分配
     大多数情况下,对象在新生代Eden区中分配。当Eden区没有足够空间进行分配时,虚拟机将发起一次 Minor GC
     Eden区与servivor区为 8:1的比例划分,其中servivor有两个,其中一个和 Eden共同形成了新生代区域。回收时,将其中一个servivor和Eden还存活的对象复制到另一个servivor里,如果servivor内存不足时,就把存活的对象复制到老年区

2.大对象直接进入老年代
     写程序时应该避免“朝生夕灭”的 短命大对象,因为会出现大对象容易导致内存还有不少空间时就提前出发垃圾收集以获取足够的连续空间来安置它们
     虚拟机提供了一个-XX:PretenureSizeThreshold参数,令大于这个设置值得对象直接再老年代分配。这样做的目的是避免在Eden区以及两个Survivor区之间发生大量的内存复制
     注意:PretenureSizeThreshold参数支队Serial和 ParNew两款收集器有效

3.长期存活的对象将进入老年代
     虚拟机给每个对象定义了一个对象年龄计数器。如果对象在Eden出生并经过第一次Minor GC后仍然存活,并且能被Servivor容纳的话,将被移动到survivor空间中, 并且该 对象年龄设为1对象在survivor区中每熬过一次minor gc ,年龄杰增加1岁,当他的年龄增加到一定程度(默认为15岁),就将会被晋升到老年代中。对象晋升老年代的年龄阈值可以通过参数 -XX:MaxTenuringThreshold 设置

4.动态对象年龄判定
     如果在Surivor 空间中相同年龄所有对象大小的综合大于 survivor空间的一半,年龄大于或等于该年龄的对象就可以直接进入老年代,无需等到MaxTenuringThreshold 中要求的年龄      

5.空间分配担保
     在发生 minor GC 之前,虚拟机会先检查老年代最大可用的连续空间是否大于新生代所有对象的总空间,如果成立,则minor gc没问题
     如果不成立,则看 HandlePromotionFailure设置值是否允许失败,如果不允许,则发生Full GC;如果允许,就检查老年代最大可用的连续空间是否大于历次晋升到老年代对象的平均大小,如果大于,则尝试着进行一次Minor GC,尽管存在风险;如果小于,则进行Full GC


总结:
1.GC是什么?
     GC 是 garbage collection,是垃圾回收机制

2.为什么要进行GC?
     为了防止内存泄露 和 溢出,腾出空间,当需要进行内存分配时,能够有空间内存进行分配,

3.什么时候进行GC?



你可能感兴趣的:(jvm,垃圾收集器,内存分配与回收策略,GC做的事情)