Java的垃圾回收机制笔记

Java的垃圾回收机制笔记

java垃圾回收的意义

  1. 确保不再被引用的对象的内存空间被回收。
  2. 确保被引用的对象的内存不被错误回收。
  3. 再分配内存。

java垃圾回收的常用方法

引用计数收集器

堆中的每个对象(不是对象的引用)都有一个引用计数。当一个对象被创建时,给该对象分配一个变量,该变量计数设置设置为1.当任何其他变量被赋值为这个对象的引用,计数加1(a=b,则b引用的对象计数+1),但当一个对象的某个引用超过生命周期或者被设置为一个新值的时候,引用的计数减1(a=c,则a不再指向b指向的对象,而指向c引用指向的对象,所以b引用的对象计数-1,而c的+1).任何引用计数为0的对象可以被当作垃圾回收。当一个对象被垃圾回收时,它引用的任何对象计数减1(a=null,此时c引用的对象计数-1)。

优点:引用计数收集器可以快速执行。 缺点:无法检测出循环引用。例如

class Main{
    public static void main(String[] args){
        Person zhang = new Person();
        Person wang = new Person();

        zhang.object = wang;
        wang.object = zhang;

        zhang = null;
        wang = null;
    }
}

class Person{
    public Object object = null;
}

虽然zhang和wang两个对象最后已经被赋值为null,zhang和wang所指向的对象已经不会被访问,但是由于zhang和wang互相应用对方,所以二者的引用计数并不为0.

对象引用遍历(跟踪搜集器)

对象引用从一组对象开始,沿着整个对象图上的每条链接,递归确定可到达(reachable)的对象。如果某个对象不能从这些根对象的一个(至少一个)到达,则把它作为垃圾回收。会有三个过程,

  1. 标记(marking)对象,标记哪些对象可以到达。
  2. 清除(sweeping)不可达到的对象。
  3. 压缩(compacting)剩余的对象,重新组织内存中的对象,形成可以利用的内存空间。

典型的垃圾收集算法

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

分成两个阶段,第一个阶段是,标记所有被回收的对象;第二个阶段是,回收被标记对象所占用的空间。

技术分享

该算法的弊端是,易产生内存碎片。

Copying(复制)算法

为了解决Mark-Sweep算法的弊端,复制算法把内存按照容量划分为大小相等的两块,每次只是用其中的一块。但这一块内存用完了,就将还存活的对象复制到另外一块上面,然后把已经使用的内存空间一次清理掉,这样不易出现内存碎片。

技术分享

不易产生内存碎片,弊端也显而易见,内存利用率太低,如果存活对象很多,效率也会很低。

Mark-Compact(标记整理)算法

为了解决Copying算法的弊端,标记整理算法提出了。该算法标记阶段与Mark-Sweep一样,但是在完成目标标记之后,不是直接清理可回收对象,而是将存活对象向一端移动,然后清理掉端边界以外的内存。

技术分享

比较理想的算法了。

Generational Collection(分代收集)算法

主流算法。核心思想是根据对象存活的生命周期将内存划分为若干个不同的区域。一般情况下,将堆划分为老年代(Tenured Generation)和新生代(Young Generation)。老年代每次垃圾回收时只有少量对象需要回收,而新生代每次垃圾回收时都有大量对象需要被回收。

新生代一般采取Copying算法。而且实际上并不是按照1:1的比例划分新生代空间的。而是划分为一块较大的Eden空间和两块较小的Survivor空间,每次使用Eden空间和其中的一块Survivor空间,回收时,将Eden空间和Survivor中还存活的对象复制到另一块Survivor空间内,然后清理掉Eden空间和刚才使用的Survivor空间。

老年代一般使用Mark-Compact算法。

与java垃圾回收相关的方法

System.gc()

使用System.gc()可以不管JVM使用的是哪一种垃圾回收算法,都可以请求垃圾回收。但是调用了System.gc()只是向JVM提出了垃圾回收的请求,JVM接受这个消息之后,并不一定立即做垃圾回收,而是对几个垃圾回收算法做加权,使垃圾回收更加容易发生,或提早发生,或回收较多。

finalize()方法

在JVM垃圾回收器收集一个对象之前,一般会要求程序调用适当的方法释放资源,但是在没有明确释放资源的情况下,java提供了缺省机制来中止该对象释放资源,这个方法就是finalize()方法。它的原型是:

protected void finalize() throws Throwable

在finalize()方法返回之后,垃圾回收开始执行。

使用fianlize()的原因是存在着垃圾回收器不能处理的特殊情况:

  1. native method中调用了C/C++的malloc()方法,但是又没有调用free函数。
  2. 打开的文件资源。

参考资料:

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。