JVM之GC算法

1、什么是GC

JVM GC是:JVM的垃圾回收算法,如今的JVM基本采用分代收集,Young区收集频繁,Old区收集较少,Perm(永久代)基本不回收;JVM进行GC时大部分是对新生代的回收,少许的全局回收。html

GC按照做用的区域分为:算法

Minor GC:做用于新生代数据结构

Major GC(Full GC):做用于老年代,偶尔也会回收老年代和永久代。spa

2、如何定位垃圾

一、引用计数法线程

 引用计数算法很简单,它其实是经过在对象头中分配一个空间来保存该对象被引用的次数。若是该对象被其它对象引用,则它的引用计数加一,若是删除对该对象的引用,那么它的引用计数就减一,当该对象的引用计数为0时,那么该对象就会被标记为垃圾对象。指针

第10行 str引用了“ABC” 则“ABC”的计算器等于1。第11行str释放了该引用,因此“ABC”的计数器就减一。
优势:实现简单,断定高效,能够很好解决大部分场景的问题。
缺点:orm

  • 很难解决对象之间相互循环引用的问题,当两个对象再也不被访问时,由于相互引用对方,致使引用计数不为0;
  • 开销较大,频繁且大量的引用变化,带来大量的额外运算;主流的JVM都没有选用引用计数算法来管理内存;

二、可达性分析法(根搜索算法)htm

可达性分析法:经过一系列"GC Roots"对象做为起始点,开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连时,认为该对象不可达,则证实该对象是不可用的;
优势:对象

  • 更加精确和严谨,能够分析出循环数据结构相互引用的状况;
  • 主流的调用程序语言(Java、C#等)在主流的实现中,都是经过可达性分析来断定对象是否存活的。

缺点:blog

  • 实现比较复杂;
  • 须要分析大量数据,消耗大量时间;
  • 分析过程须要GC停顿(引用关系不能发生变化),即停顿全部Java执行线程(称为"Stop The World",是垃圾回收重点关注的问题);

哪些对象能够做为GC ROOT对象(GCRoot 能够是一个也能够是多个):

  • 一、虚拟机栈(栈桢中的局部变量区,也叫局部变量表)中引用的变量
  • 二、方法区中类的静态属性引用的对象
  • 三、方法区中常量引用的对象
  • 四、本地方法栈中JNI(Native)引用的对象

 3、垃圾回收算法

一、标记-复制:它将可用内存容量划分为大小相等的两块,每次只使用其中的一块。当这一块用完以后,就将还存活的对象复制到另一块上面,而后在把已使用过的内存空间一次理掉。

JVM实现原理:Survivor区,一块叫From,一块叫To,对象存在Eden和From块。当进行GC时,Eden存活的对象全移到To块,而From中,存活的对象按年龄值肯定去向,当达到必定值(年龄阈值,经过-XX:MaxTenuringThreshold可设置,默认=15)的对象会移到年老代中,没有达到值的复制到To区,而后直接清空Eden和From。以后,From和To交换角色,新的From即为原来的To块,新的To块即为原来的From块,且新的Form块中对象年龄加1.
优势:内存分配时也不用考虑内存碎片等问题;实现简单,运行高效;能够利用指针碰撞(bump-the-pointer)实现快速内存分配
缺点:

  • 空间浪费:可用内存缩减为原来的一半,太过浪费(解决:能够改良,不按1:1比例划分);
  • 效率随对象存活率升高而变低:当对象存活率较高时,须要进行较多复制操做(对象的引用地址须要复制),效率将会变低,因此该算法不适合对象存活率较高的场景或者区域。

应用场景:

  • 如今商业JVM都采用这种算法(经过改良缺点1)来回收新生代;
  • 如Serial收集器、ParNew收集器、Parallel Scavenge收集器、G1(从局部看)。

二、标记-清除:首先标记出须要回收的对象,标记完成以后统一清除对象。

标记:从根集合开始扫描,标记存货的对象
清除:扫描整个堆内存空间,回收未被标记的对象,使用free-list记录可使用的区域

优势:基于最基础的可达性分析算法,它是最基础的收集算法;然后续的收集算法都是基于这种思路并对其不足进行改进获得的;
缺点:

  • 效率问题:标记和清除都须要扫描,两个过程的效率都不高;
  • 空间问题:标记清除后会产生大量不连续的内存碎片,这会致使分配大内存对象时,没法找到足够的连续内存,从而须要提早触发另外一次垃圾收集动做。
  • stop-the-Word:在标记时须要暂停JVM用户进程

应用场景:针对老年代

三、标记-整理

 

标记-整理:标记操做和“标记-清理”算法一致,后续操做不仅是直接清理对象,而是在清理无用对象前,先将存活的对象都向一端移动,并更新引用其对象的指针,而后直接清理掉端边界之外的内存。

标记:和“标记-清理”算法一致

整理:扫描整个堆内存空间,将存活的对象都向一端移动,并更新引用其对象的指针,而后直接清理掉边界之外的内存。整理的目的就是整合零散分布的空间碎片为一个连续的空间。

优势:

  • 不会像复制算法,效率随对象存活率升高而变低
  • 不会像标记-清除算法,产生内存碎片,由于清除前,进行了整理,存活对象都集中到空间一侧;

缺点:主要是效率问题:除像标记-清除算法的标记过程外,还多了须要整理的过程,效率更低;
应用场景:回收老年代;
四、标记-清除-整理(Mark-Sweep-Compact)
  该算法是标记清除和标记整理的结合,标记-清除会产生碎片,标记-整理每次都进行整理效率不高;标记-清楚-整理 是若是老年代内存中没有一块连续续的空间能够存放将要进入对象,就进行整理;若是内存中的空间能够存放将要进入的对象,就进行标记-清除,这样就节省了整理的步骤能够提升效率。总结一句话:不是全部的时候都须要整理的,由于整理也付出代价。主要应用于老年代

总结: 没有最好的算法,只有最合适的引用场景

 

 

 下一节:GC算法的实现

相关文章
相关标签/搜索