jvm(四):垃圾回收

  垃圾回收我们主要从以下三个方面进行描述

  

  垃圾对象的判断 

  目前判断对象为垃圾对象有两种方法:引用计数法,可达性分析法,目前普遍是的是可达性分析法

  可达性分析法的实现原理:

  定义gcroot一直往下找,如果能找到对象,证明该对象在使用,如果找不到该对象,标记该对象应该回收。上图中栈作为gcroot只是其中一种情况,可作为gcroots的对象有虚拟机栈(栈帧中的局部变量表),方法区的类属性所引用的对象,方法区中常量所引用的对象,本地方法栈中引用的对象。

  引用计数法的实现原理:

  在对象中添加一个引用计数器,当有地方引用这个对象的时候引用计数器的值就+1,当引用失效的时候,计数器的值就-1,问题就是,如果a、b引用断开,这时候A、B对象计数器的值都是1,所以当循环引用的时候,不能进行垃圾回收。我们可通过代码试验此过程,注意我们需要配置以下虚拟机参数才可以看到垃圾回收日志:

  垃圾回收算法

  常见的垃圾回收算法有标记-清除算法,复制算法,标记-整理算法,分代收集算法。

  标记清除算法:

  此算法分为两个阶段,标记阶段(找到所有可访问的对象进行标记)和清除阶段(遍历堆把未被标记的对象清除)

  此算法主要存在两方面的问题,效率问题和空间问题。这样会使不连续的空间越来越多,实在找不到空间的时候回触发再一次的垃圾回收。

  标记整理算法

  标记整理算法可以说是标记清除算法的升级版,标记整理算法也分为两个阶段,标记和整理,标记阶段是和标记清除算法的第一阶段一模一样的,均是遍历GC Roots,将存活的对象标记;在整理阶段会移动所有存活的对象,且按照内存地址次序依次排序,然后将末端内存地址以后的内存全部回收。

  因为需要整理内存,与标记清除算法相比,标记整理算法需要花费更多的时间。

  

  复制算法

  复制算法将堆上的内存分为大小相等的两个区域,一个是活动区域,一个是空闲区域。在程序运行过程中使用活动区域,也就是有一半的空间被浪费掉

  首先找出活动空间中所有存活的对象,将这些对象复制到空闲区域,将之前的活动空间清空,并变为空闲空间,存货对象所在的区域变为活动区域,这样就能保证在内存回收完毕后有一大片连续的可用空间。

  分代回收算法

  当前商用虚拟机基本都采用分代垃圾回收算法来回收垃圾,它主要是根据对象的生命周期将内存划分,然后进行分区管理

  分代垃圾回收机制将堆空间分为新生代和老年代,新生代又被分为Eden区,From区,To区。当创建一个对象的时候,在Eden区进行操作,当Eden区内存不足的时候,会触发一次YoungGC(年轻代的垃圾回收),将存活的对象复制到From区,Eden区被清理,并继续创建新的对象,当内存再次不足的时候再次触发YoungGC,将Eden区与From区存活的对象复制到To区,下一次YoungGC的时候,将Eden区与To区中存活的对象复制到From区,经过若干次YoungGC后,还存活的对象会被复制到老年代。

  垃圾收集器

  serial收集器:最基础,发展最悠久的单线程垃圾收集器,适合桌面应用,适用于内存分配比较小,收集垃圾比较快的应用。

  如有四个java线程在运行,垃圾收集时java线程停止,垃圾收集后,java线程继续进行。

  parnew收集器:parnew收集器是是serial收集器的多线程版本,使用多线程进行垃圾收集(一般用于新生代收集器)

  

parallel Scavenge收集器:采用复制算法的多线程收集器,可达到可控制的吞吐量(cpu用于运行用户代码的时间与cpu消耗的总时间的比值(垃圾收集时间+用户代码执行时间)),可用-XX:MaxGCPauseMillis来设置,垃圾收集器的最大停顿时间,用-XX:GCTimeRatio来设置吞度量大小。此收集器与parnew比较相似,但是对吞度量要求比较高。

  CMS收集器

  CMS收集器是基于标记-清除算法实现的,其运作步骤为初始标记,并发标记,重新标记,并发清除(一般用作老年代收集器)

  其中,初始标记,重新标记需要停止正在运行的java线程,初始标记是标记一下GCRoots能直接关联到的对象,速度很快,并发标记是GC Roots Tracing的过程(根据可达性分析法进行关联的过程),重新标记是为了修正并发标记期间,因用户程序继续运作而导致标记产生变动的对象的标记记录,这个阶段停顿的时间比初始标记稍长,但远比并发标记的时间短。可以看出,CMS收集器的耗时时间长的过程都可以与用户线程一起并发的执行。

  G1收集器

  G1收集器具有并行与并发结合,分代收集,空间整合,可预测的停顿等特点,采用标记整理算法,G1收集器不会产生空间碎片,分配大对象时不会因为无法找到连续空间而提前触发下一次GC,G1收集器能让使用者明确在一个长度为N毫秒的时间片段内,消耗在垃圾收集上的时间不能超过多少,上面提到的收集器收集的范围都是整个新生代或者老年代,而G1将java堆划分为多个大小相等的独立区域(Region),新生代和老年代不再是物理隔阂了。

  

  

  

  

猜你喜欢

转载自www.cnblogs.com/sbrn/p/8954955.html