JVM的垃圾回收机制

        垃圾回收(Garbage Collection),是JVM中重要的一部分,Java和C++一个很大的不同就是Java中的垃圾回收机制。要了解JVM的垃圾回收机制,需要了解哪些对象需要回收?使用什么方式回收?下面就参考《深入了解Java虚拟机》做下总结,主要以HotSpot虚拟机为例。

 

如何确定对象是否该被回收?

 

        判断对象是否该被回收有两种方式,引用计数算法和可达性分析算法。

 

引用计数算法

 

        引用计数算法是这样的:对于一个对象A,只要有任何一个对象引用了A,则A的引用计数器就加1;当引用失效时,A的引用计数器就减1。只要对象A的引用计数器的值为0时,则对象需要被回收。

 

        引用计数算法是一个老牌的垃圾回收算法,有一些技术也在使用这种算法来管理内存。但是Java虚拟机中没有使用这种方式,它有两个问题,一是引用的加减法会影响性能;但是主要问题是第二个,它无法解决循环引用的对象的垃圾回收。

 

例如:

 

Object objA = new Object();
Object objB = new Object();
objA.instance = objB;
objB.instance = objA;

 

 

        此时当不再使用这两个对象时,因为两个对象互相引用,所以彼此的引用计数器都不为0,导致两个对象无法被GC。所以这种方法在Java虚拟机中没有实现,Java虚拟机主要用的是第二种,可达性分析算法。

 

可达性分析算法

 

        可达性分析算法会定义一系列GC Roots的对象来作为根节点,从这些节点向下搜索,所走过的路径称为引用链,类似于图的结构。当一个对象从GC Roots开始没有任何的引用链可以到达时,则判定该对象是不可用的,会被判定为可回收的对象。

 

   

 

在Java虚拟机中,可以作为GC Roots的对象包括以下几种:

        1、虚拟机栈(栈帧中的本地变量表)中引用的对象

        2、方法区中类静态属性引用的对象

        3、方法区中常量引用的对象

        4、本地方法栈中JNI(Native方法)引用的对象。

 

引用的类型

 

        无论是引用计数算法还是可达性分析算法,判断对象是否要被回收,都和引用有关。Java中原本的引用定义是,如果reference类型的数据中存储的数值代表的是另外一块内存的在其实地址,就称为这块内存代表着一个引用。在JDK1.2之后,Java对引用的概念进行了扩充,分为了强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)、虚引用(Phantom Reference)四种,这四种的引用强度依次减弱。

 

        强引用:强引用类似于“Object object = new Object()”这样的引用,只要强引用存在,垃圾收集器就不会对这些对象进行回收

 

        软引用:软引用是用来描述一些还有用但非必要的对象,有软引用的对象会在发生内存溢出异常之前,被列入下一次回收的范围内。如果这些对象进行垃圾回收以后内存还是不够,则会引起内存溢出异常。

 

        弱引用:弱引用关联的对象是非必须对象,往往只能生存到下一次垃圾收集发生之前。当发生垃圾回收时,无论内存是否足够,这部分对象都会被回收。

 

        虚引用:虚引用是最弱的一种引用关系,它对对象的生存时间不会构成影响,也无法通过虚引用来取得一个对象实例。为一个对象设置虚引用关联的唯一目的就是能在这个对象被收集器回收时收到一个系统通知。

 

垃圾回收算法

 

标记-清除算法

 

        标记-清除算法是最基础的收集算法,它分为标记和清除两个部分。首先标记处所有需要回收的对象,在标记完成后统一回收所有被标记的对象。不过标记-清除算法有两个问题:一是效率问题,标记和清除两个过程效率都不高;二是控件问题,对象被清除之后,会产生大量的不连续的内存碎片,大量的空间碎片可能会导致以后再需要分配较大对象时,无法找到足够的连续内存而提前触发再一次的垃圾收集。

 

          

        上图中白色:空闲空间;黑色:垃圾对象;灰色:存活对象。

 

复制算法

 

        为了解决标记-清除算法的效率问题,出现了复制算法。复制算法将可用内存划分为大小相等的两块,每次只使用其中的一块。当需要垃圾回收时,将这一块上存活的对象都复制到另外一块内存中,然后将这一块内存完全清理掉。只不过这种算法仍然后问题,那就是空间成本太大。

 

                                   

 

标记-整理算法

 

        标记-整理算法在标记-清除算法的基础上,增加了整理内存的过程,解决了之前产生的内存碎片问题。

 

  

  上图中白色:空闲空间;黑色:垃圾对象;灰色:存活对象。

 

分代思想

 

        分代思想是根据对象的存活周期进行分类,不同的存活周期分为不同的代。如存活周期较短的对象归为新生代,存活周期较长的分为老年代。针对新生代和老年代不同的对象特点,使用不同的垃圾回收方式进行回收。

 

        新生代:新生代的对象存活周期短,每次垃圾回收时都会有大量的对象需要被回收,而存活的对象较少,所以利用复制算法进行垃圾回收。在新生代进行垃圾回收时,复制算法也不一定是严格的将内存对半分,可以将内存分为一块较大的Eden区和两个较小的Survivor区。

 

                                                                               

 

        s0和s1分别代表From Survivor和To Survivor区,当需要垃圾回收时,将Eden和From Survivor区的存活对象都复制到To Survivor区中,然后将Eden和From Survivor全部清理掉。HotSpot虚拟机默认将Eden和Survivor的大小比例设置为8:1,也就是新生代的内存区中,Eden占80%,两块Survivor区各占10%。

 

        老年代:老年代中的对象都是存活周期比较长的对象,所以垃圾回收的频率也不是很高,每次收集的对象也不会很多,所以会采用标记-清除算法或者标记-整理算法来进行回收,性能的影响也不算很大。

 

总结

 

        JVM虚拟机垃圾回收已然是自动化执行的功能,但是了解垃圾回收机制可以更好的了解内存溢出异常发生在哪个位置,发生在什么情况下。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值