JVM垃圾回收算法

1 概述

前面已经介绍过了,jvm运行时的数据区域包括程序计数器、虚拟机栈、本地方法栈、堆和方法区,其中程序计数器、虚拟机栈和本地方法栈是线程私有的,当方法结束或者线程销毁时,这部分的内存就会被回收了,不用过多的考虑。所以,本章所讲的主要是堆和方法区的内存分配与回收问题。

2 对象“死”了吗

我们知道,堆里面几乎存放了java中所有的对象实例,垃圾收集器(GC)在对这部分内存进行回收时,首先需要判断对象是否还存活着,然后将“死”的对象或者是没有必要存活下去的对象进行回收。

2.1 引用计数算法

引用计数算法就是给每个对象添加一个计数器,当有地方引用它的时候,计数器就加1,当引用消失时,计数器就减1,计数器为0的对象可以认为该对象没有被引用,可以被垃圾收集器回收。不过,目前主流的java虚拟机并没有采用这种算法,主要原因是难以解决对象间相互引用的问题,即:Object A = B, Object B = A.

2.2 可达性分析法

可达性分析法就是通过从一系列称之为“GC Root”的点开始出发,向下面所有的对象开始搜索,如果“GC Root”无法到达一个对象,则这个对象就会被认为是可以被回收的对象,就会被垃圾收集器回收。
可以作为GC Root对象的主要有以下几种:

  • 虚拟机栈中引用的对象
  • 方法区中类静态属性引用的对象
  • 方法区中常量引用的对象
  • 本地方法栈中JNI引用的对象
Java中的引用主要分为强引用、软引用、弱引用和虚引用。强引用的对象是不会被垃圾收集器回收的,软引用对象会被放到二次回收的范围内进行第二次回收,如果第二次回收后内存还是不够,就会报内存溢出异常,弱引用和虚引用都会被垃圾收集器回收掉。
2.3 To be or not to be

当一个对象被认为是可回收的时候,也不一定就会被回收,它们首先会被进行一次回收标记,然后判断这个对象是否有必要执行finalize()方法,如果没有必要执行或者是finalize()方法已经被jvm执行过了,那么这个对象就幸运的活了下来。当然,就算是认为有必要执行finalize()方法或者是jvm还没有执行finalize()方法,这个对象还是有机会活下来的。当一个对象在执行finalize()方法的时,只要重将自己与GC Root连接到,即GC Root与该对象是可到达的,那么这个对象就会被标记会“即将回收”,如果这个时候还没有拯救出自己的话,那么就会被垃圾收集器回收掉。另外需要注意一点的是,一个对象的finalize()方法只会执行一次,也就是说一个对象只要一次自救的机会。

3 垃圾回收算法思想
3.1 标记-清除算法

这种算法的思想就是将要回收的对象标记起来,然后统一的将这些对象清除掉,这是最基本的一种回收思想,不过这种算法有两个不足点:一个是效率问题,因为标记和清除两个操作效率都不高,二是空间问题,因为这种回收算法会导致大量的内存碎片,当需要一个很大内存空间来存储对象时,有时会难处理。

.3.2 复制算法

这种算法的思想就是将内存分成两部分,分配内存时只使用一部分,当垃圾回收时,将未回收的复制到另一部分内存中,这样虽然不会产出内存碎片,但是会浪费一半的内存使用空间。

3.3 标记-整理算法

这种算法思想首先是标记要回收的对象,然后将要清理的对象向一边移动,不需要回收的对象向另一边移动,最后直接将需要清理的对象回收掉即可。

3.4 分代收集算法

这种算法是根据对象不同的存活周期划分为几块,一般分为新生代和老年代,根据不同年代的特点采取不同的回收算法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值