你的位置:首页 > Java教程

[Java教程]jvm中的垃圾回收


一、垃圾回收的概念

   Java中的内存回收即Jvm运行时的内存的回收,需要回收的区域有方法区和Java堆。由于程序计数器,Java虚拟机栈和本地方法栈在方法结束或者是线程结束时会自动进行回收所以无须考虑回收。为什么需要垃圾回收呢?因为电脑中的内存的大小是有限而固定的,在运行过程中由于类的加载和创建,内存中已使用的内存会越来越大,导致后来的程序执行时无法进行分配内存进行执行,此时就需要进行垃圾回收,将已经使用的内存区域中没有在使用的数据清除,从而使后来的程序能够正常运行。

二、如何判断一个对象可以进行回收?

  在进行垃圾回收的时候,如何判断一个对象是否已经可以进行回收了呢?一个对象可以进行回收的时候就是不再有变量引用这个对象。常规去判断一个对象是否还有变量引用,使用的是引用计数法。就是给对象添加一个引用计数器,如果一个变量引用了这个对象,就把计数器里面的值加一,引用失效时就减一。进行垃圾回收的时候,对计数器里面的值为零的对象进行回收。但是主流的Java虚拟机并没有采用此种方法进行垃圾回收,而是采用GC Roots可达性算法进行判断一个对象是否可以进行回收。

  采用GC Roots可达性算法进行判断对象是否回收时,就是通过一系列可以作为GC Roots的对象作为起始点,向下搜索对象,形成多条对象可以GC Roots对象的路径,称为引用链,当一个对象不存在这个引用链中时,就可以进行回收。

  

  图中的对象A、B、C、D都存在路径(引用链)到达GC Roots对象,F则不存在,所以进行内存回收会回收对象F,而不会回收对象A,B,C,D。

三、垃圾回收算法

  Jvm中的内存回收使用以下几种回收算法:

  1.标记-清除算法:在进行垃圾回收的时候,将不再引用的对象进行标记,标记完成后,统一对于标记的对象进行回收。

  未回收时:

  

 

  进行标记-清除时,会对未引用对象进行全部标记,在标记完成后,对标记的未引用对象的内存进行回收。

  标记-清除后:

  

  2.标记-整理算法:在进行垃圾回收的时候,将不再引用的对象进行标记,标记完成后,统一对于标记的对象进行回收后,对内存进行整理,将引用对象移动到一起

  标记-整理之前:

  

  如同标记-清除方法一样,会对未引用对象进行标记,标记完成后进行清除,然后将还在引用对象的内存移动到一起

  标记整理后:

      

  3.复制算法::将内存划分成相等的两块内存,每次只使用其中一块内存进行分配,当正在使用内存中的空间使用完毕时,将使用的内存中的还存活的对象复制到另一块未使用的内存上,然后将清理已使用内存的空间。

  回收之前:

   

  复制算法回收之后:

  

  4.分代算法:将回收区分为新生代和老年代,新生代采用复制算法,老年代采用标记-清除或者是标记-整理算法

四、垃圾收集器  

  垃圾收集器就是垃圾回收算法的具体实现。Jvm中存在一下几种垃圾收集器

  

  1.Serial收集器:使用单线程对于垃圾进行回收,进行垃圾回收时必须停掉所有得工作进程进行垃圾回收,使用标记-整理算法。

  2..Serial Old收集器:Serial收集器的老年代版本。

  3.ParNew收集器:Seria收集器的多线程版本。

  4.Parallel Scavenge收集器:采用复制算法的收集器,控制吞吐量进行垃圾收集的算法,吞吐量即CPU运行用户代码的时间与CPU运行总时间的比值,用户可以通过设置吞吐量来控制垃圾回收的效率。

    5.Parallel Old收集器:Parallel Scavenge的老年代版本,采用标记整理算法和使用多线程回收。

  6.CMS收集器:以获得最短回收停顿时间为目标的收集器,采用标记-清除算法。回收的流程为:初始标记->并发标记->重新标记->并发清除.

  7.G1收集器:最新的收集器,回收流程为:初始标记->并发标记->最终标记->筛选回收。