JVM 垃圾回收机制

目录

 

1. 如何判断一个对象是否已死

1.1 引用计数法

1.2 根搜索算法

1.22 根搜索算法的后续

2. 方法区回收

3. 垃圾回收算法

3.1 标记——清除算法

3.2 复制算法

3.3 标记——整理算法

3.4 分代收集算法


1. 如何判断一个对象是否已死

堆是垃圾回收器(Garbage Collection,简称GC)主要针对的地方,所以判断对象是否已死很重要。

程序计数器、虚拟机栈、本地方法栈都是线程私有的,所以这三个区域随线程的创建而生,随线程的销毁而亡。

方法区就是所谓的永久代,对于永久代,有相应的回收策略。

如果GC采用的是分代收集算法的话,堆被分为新生代和老年代,新生代用的是复制算法(Eden 和 Surviver 这种),老年代使用的是“标记——整理”算法。

对于不同的代,有相应的垃圾回收器,而不是一个垃圾回收器就搞定所有,垃圾回收器可以搭配着协作。

1.1 引用计数法

在对象内部添加一个引用计数器,记录这个对象有多少个引用,每当有一个地方引用它的时候就加1,每当有一个引用失效的时候,就减1,当引用计数器为0的时候,就表示对象不可能再被使用了,此时就被判定为可回收对象。

引用计数法的优点:简单高效。

引用计数法的主要缺点:很难解决对象之间相互引用。

举个例子:

1句和2句创建了两个对象,然后这两个对象分别有了一个引用,此时各自的引用计数器=1,然后3、4句中,这两个对象又被引用了一次,引用计数器=2,5、6句毁了两个引用,计数器=1,此时两个对象已经无法被使用了,但是不会被回收,因为引用计数器不为0。

1.2 根搜索算法

Java语言虚拟机中就使用的是根搜索算法。

算法思路:将一系列名为“GC Roots”的对象作为根节点,开始向下搜索,能够搜索到的(到达的)对象,就是仍然有效的,无法到达的对象,就会被判定为可回收对象。

 

两个算法比较之下,明显根搜索算法更好,总之,这两种算法都与引用有关,引用有四种类型:强引用、软引用、弱引用、虚引用。

1.22 根搜索算法的后续

并不是无法到达的对象就一定死定了,因为GC回收对象之前需要执行finalize()方法,具体的原理:当发现某个对象与根对象失去连接之后,就给对象做一个标记,然后判断这个对象的finalize()方法:如果方法被虚拟机调用过了,或者没有被重写,就意味着该对象的finalize()方法没有必要执行了,然后GC对其做第二次标记;否则,finalize()方法就需要执行,虚拟机会将这个对象放到一个名为F-Queue队列中,随后虚拟机会创建一个低优先级的Finalizer线程去执行队列中那些对象的finalize()方法,只要触发了finalize()方法就算是调用过了,并不会保证让finalize()方法执行完,正常情况下是会让方法执行完的,但是对于那些执行非常缓慢,或者发生了死循环的finalize()方法,就不会等待其执行完。如果在finalize()方法中将该对象重新引用,使得根对象能够与之相连,那么这个对象就活了,不用死了。finalizer线程运行后,GC对队列中的对象再检查一次,是否还是与根对象断开,如果又连接上了,就不回收它,如果还是断开的,就给对象做第二次标记。对于有两次标记的对象,GC就会回收。

还有,那些在finalize()方法中又活过来的对象,如果下一次再与根对象断开,那就再也活不过来了,因为它的finalize()方法已经被虚拟机调用过了

我们大可不用管1.22中的内容,因为java基本不用finalize()方法了,因为还有其他的方式可以比finalize()方法做得更好,既然finalize()方法不被重写了,那就是一旦对象与根对象断开,那就必死无疑,定被回收。

2. 方法区回收

3. 垃圾回收算法

3.1 标记——清除算法

首先将可以回收的对象做标记,标记完了之后,进行回收,与上文讲的那个标记是一个意思。有两个缺点:1,效率不高,2,回收之后,产生大量内存碎片,如果需要为一个大对象分配空间的话,就需要对碎片进行整理,腾出连续的内存空间,如果不顾的话,就可能需要再一次进行内存回收,以空出能够分配的内存。

3.2 复制算法

将内存划分为相等的两块A,B,每次只用其中的一块,假如这次是A,回收一次垃圾之后,会留下仍然存活的对象,内存也是多碎片的,将这些对象复制到另一块内存B里,内存连续存储,这样碎片问题解决了,将之前的那块内存A清除干净,然后使用现在这个内存B,等到了回收的时候,就回收,然后将存活的对象又复制到A中去,清理干净B。如此循环。

优点:高效,简单。

缺点:内存成本大。

Survivor区,一块叫From,一块叫To,对象存在Eden和From块。当进行GC时,Eden存活的对象全移到To块,而From中,存活的对象按年龄值确定去向,当达到一定值(年龄阈值,通过-XX:MaxTenuringThreshold可设置)的对象会移到年老代中,没有达到值的复制到To区,经过GC后,Eden和From被清空。

  之后,From和To交换角色,新的From即为原来的To块,新的To块即为原来的From块,且新的To块中对象年龄加1.

3.3 标记——整理算法

3.4 分代收集算法

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值