6.GC算法

一、GC概念
  • GC定义:

   Garbage Collection 垃圾收集。这里所谓的垃圾指的是在系统运行过程当中所产生的一些无用的对象,这些对象占据着一定的内存空间,如果长期不被释放,可能导致OOM。

  • 为什么引入GC:

   由于Java不像c/c++那样可以由程序猿去控制内存空间的分配、管理、释放,因此引入GC,目的防止人为导致的内存泄露。

  • GC作用内存区域:

   堆和方法区。内存区域中的程序计数器、虚拟机栈、本地方法栈这3个区域随着线程而生,线程而灭;栈中的栈帧随着方法的进入和退出而有条不紊地执行着出栈和入栈的操作,每个栈帧中分配多少内存基本是在类结构确定下来时就已知的。在这几个区域不需要过多考虑回收的问题,因为方法结束或者线程结束时,内存自然就跟着回收了。而堆和方法区是空间大小是动态分配和动态回收的。

  • 触发GC的条件:

   ①、程序调用System.gc时可以触发;

   ②、系统自身判断GC的依据:根据Eden区和From Space区的内存大小来决定。当内存大小不足时,则会启动GC线程并停止应用线程。

二、GC算法
1、引用计数算法(Reference counting):老牌垃圾回收算法。无法处理循环引用,没有被Java采纳

  原理:给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加1;当引用失效时,计数器值就减1;任何时刻计数器为0的对象就是不可能再被使用的。

  缺点:无法解决对象相互循环引用的问题,且每次对对象复制时均要维护引用计数器,且计数器本身也有一定的消耗。

2、复制算法(Copying):

  原理:它先将可用的内存按容量划分为大小相同的两块,每次只是用其中的一块。当这块内存用完了,就将还存活着的对象复制到另一块上面,然后把已经使用过的内存空间一次清理掉。

  • 从根集合(GC Root)开始,通过追踪从From找到存活的对象,拷贝到To中;
  • From和To身份交换

  

  特点:没有内存碎片,只要移动堆顶指针,按顺序分配内存即可。代价是将内存缩小位原来的一半。
  地方:适合新生代区进行垃圾回收。serial newparallel newparallel scanvage收集器,就是采用该算法进行回收的

3、标记-清除算法(Mark-Sweep)

  原理:分为标记和清除两个阶段:首先标记出所有的需要回收的对象,在标记完成以后统一回收所有被标记的对象

  • 标记:从根集合开始扫描,对存活的对象进行标记;

  

  • 清除:扫描整个内存空间,清除未被标记的对象。

  

  特点:相比复制算法,利用Survivor的内存空间效率更高些。但也留下了两个缺点:

  ①、效率问题,执行了两次扫描,耗时严重,因此效率不高;

  ②、空间问题,留下了不连续的内存碎片,可能导致程序运行过程需要分配较大的对象时候,无法找到足够连续内存而不得不提前触发一次垃圾收集

  地方 :适合在老年代进行垃圾回收,比如CMS收集器就是采用该算法进行回收的。

4、标记-整理算法(Mark-Compact):

  原理:分标记和整理两阶段

  • 标记:标记出存活的对象,回收死亡的对象

 

  • 整理:让所有存活的对象都向一端移动

  

  特点:不会产生空间碎片,但整理会占用一定的开销。

  地方:适合老年代进行垃圾收集,parallel Old(针对parallel scanvange gc的) 和Serial old收集器就是采用该算法进行回收的。

三、优化收集算法思路

  原理:根据对象存活的周期的不同将内存划分为几块,然后再选择合适的收集算法,也称为分代收集算法

  根据堆分为新生代和老年代,采用不同的GC算法进行搭配。在新生代中,每次垃圾收集都会有大量的对象死去,只有少量存活,所以选用复制算法。老年代因为对象存活率高,没有额外空间对他进行分配担保,所以一般采用标记整理或者标记清除算法进行回收。


ps:关于标记-整理算法的原理,有些歧义,1、是标记存活的对象还是标记死亡的对象;2、标记的同时进行回收,还是整理后再进行回收。

 

 

 

 

 

 

猜你喜欢

转载自www.cnblogs.com/light-sunset/p/12796536.html