JVM的垃圾回收机制,在内存充足的情况下,除非你显式的调用System.gc(),否则不会进行垃圾回收;在内存充足的情况下垃圾回收会自动运行。
一、引用计数算法
1.定义:引用计数算法会给对象添加一个引用计数器,每当有一个地方引用他的时候,计数器就加1;当引用失效的时候计数器值就减1。当计数器为0的时候,对象就可以被收回。
2.缺点:存在循环引用的情况,导致两个循环引用对象的内存得不到释放。目前没有一个JVM垃圾回收实现是使用这个算法的。
3.现状:主流的Java虚拟机没有使用引用计数算法来管理内存,因为它很难解决循环引用的问题。
二、可达性分析算法
1.思路:通过一系列"GC Roots"对象作为起点,从这些节点开始向下进行搜索,搜索所走过的路径被称为"引用链"。当一个对象到GC Roots没有任何引用链相连,也就是从GC Roots到这个对象不可达,则证明此对象是不可用的。如图中Object5、Object6、Object7虽然互相关联,但是他们到GC Roots是不可达的,所以他们被判定为可回收的对象。
把一些对象当做root对象,JVM认为root对象是不可回收的,并且root对象引用的对象也是不可回收的。在Java语言中,可作为GC ROOT的对象包含以下几种:
(1)虚拟机栈(栈帧中本地变量表)中引用的队形啊
(2)方法区中静态属性引用的对象
(3)方法区中常量引用的对象
(4)本地方法栈中Native方法引用的对象。
2.即使在可达性分析法中不可达的对象,也不是非死不可的,要真正宣告对象的死亡,只要经历两次标记过程:
(1)如果对象在进行可达性分析之后,发现没有与GC Roots相连的引用链,那么它会被第一次引用。
(2)判断该对象是否有必要执行finallize(),如果对象内有覆盖finallize(),或者finallize()方法已经被覆盖过了,虚拟机将这种情况视为没有必要执行。
- 如果一个对象的finallize()方法执行缓慢,甚至发生了死循环,那么导致FQueue队列中的其他对象永远等待下去,甚至导致整个回收系统崩溃,因为在FQueue中的对象无法进行垃圾的回收。
- 如果一个对象被判定为有必要执行finalize()方法,那么这个对象将被放置在一个F-Queue的队列中,并在稍后由虚拟机建立的。低优先级的Finalizer线程去执行。这里的执行是指虚拟机会触发这个方法,但是不承诺等待该方法执行完毕,这样做的原因是:finalize()方法是对象最后一次逃脱死亡命运的机会,如果对象在finalize()方法中成功拯救自己,和引用链上的任何一个对象关联起来,比如把自己(this)赋值给某个类变量或者成员变量,那么在第二次标记的时候会被移除即将回收的集合。
- 如果对象没有成功逃脱,那么基本上会被真的回收了(第二次标记)。
任何一个对象的finallize方法只会被系统自动调用一次,如果对象面临下一次回收,他的finalize()方法不会再被执行。尽量避免finalize方法,因为它只是为了是C/C++程序员更容易接受java所做出的的一个妥协,他的运行代价高昂,不确定性高,无法表达各个对象的调用顺序。 ---未完待续
原文地址:https://www.cnblogs.com/bigdata-stone/p/12041882.html