JVM第六篇(垃圾回收机制一)

在JVM的内存结构中,堆内存中存放着创建出的对象,如果创建出的对象,长时间没有被外部引用,则会被垃圾回收。

下面从五个方面开始学习垃圾回收机制。

  1. 如何判断对象可以回收
  2. 垃圾回收算法
  3. 分代垃圾回收
  4. 垃圾回收器
  5. 垃圾回收调优

如何判断对象可以回收:
当对象长时间没有被引用,则可以考虑将其回收。
引用计数法:存在一个引用计数器,如果一个对象被引用,则计数器+1,如果对象不在被引用,则计数器-1,如果计数器为0,则说明对象没有被引用,则可以被回收。
如果对象之间存在互相引用,引用计数器就都不为0,就不能被垃圾回收,那么就形成了死锁,造成内存泄漏,如图:
请添加图片描述

可达性分析算法:就是从根对象(GC root)开始,判断对象是否被根对象直接或间接的引用,如果被根对象所直接或间接引用,则对象不能被垃圾回收。如果没有则可以被垃圾回收。(根对象就是堆中,不能被垃圾回收的对象。)

在JVM中的垃圾回收器,采用可达性分析来探索所有存活的对象。扫描堆中的对象,看是否能够沿着根对象(GC root)为起点的引用链找到该对象,找不到,则表示可以被回收。(GC root 不是一个对象,而是一系列的对象,GC roots)

哪些对象可以作为 GC Root ?

  1. System Class,系统类,程序运行时候的核心类,可以作为根对象
  2. Native Stack,本地方法,所运行时候,引用的Java类,可以作为根对象
  3. Busy Monitor,在程序中被加了锁的对象,可以作为根对象
  4. Thead,活动线程中被引用的对象,可以作为根对象

JVM中的五种引用:

  1. 强引用
  2. 软引用
  3. 弱引用
  4. 虚引用
  5. 终结器引用

请添加图片描述
在图中实线部分代表强引用,如C对象强引用A1对象,B对象强引用A1,A2,A3,A4,ByteBuffer

强引用:
在程序中,new 了一个对象,变量通过赋值运算符,引用了该对象,就属于强引用。
在图中,C对象和B对象都强引用了A1对象,在进行垃圾回收时,则不对A1对象进行回收。
如果C对象和B对象,都不再强引用A1对象,则A1对象,在垃圾回收时,会被回收。

软引用:
在图中C对象强引用了一个软引用对象,通过软引用对象间接软引用了A2对象,同时B对象强引用了A2对象,如果B对象不在强引用A2对象,在进行垃圾回收时,如果垃圾回收完成之后,还是内存不足,则会将软引用引用的对象回收。

弱引用:
在图中C对象强引用了一个弱引用对象,通过弱引用对象间接弱引用了A3对象,同时B对象强引用了A3对象,如果B对象不在强引用A3对象,在进行垃圾回收时,无论内存是否充足,都会将A3对象进行垃圾回收。
软引用与弱引用区别:软引用是在垃圾回收,内存不足,才进行回收,弱引用是在垃圾回收时,无条件回收。

软引用对象与弱引用对象可以使用引用队列来管理,如果软引用对象和弱引用对象在创建时,使用了引用队列,当软引用对象和弱引用对象,不在引用对象时,软引用对象和弱引用对象将会进入引用队列。通过引用队列来进行对软引用对象和弱引用对象所占内存进行释放。

虚引用和终结器引用与软引用和弱引用的区别,虚引用和终结器引用,必须使用引用队列,软引用和弱引用,可以不使用引用队列。

虚引用:
虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。当虚引用引用的对象被垃圾回收时,会将虚引用加入引用队列。
如图中所示:虚引用了一个ByteBuffer 对象,当ByteBuffer对象被垃圾回收,但ByteBuffer所申请的本地内存,并不会被垃圾回收,此时虚引用对象会加入引用队列,而引用队列有一个ReferenceHandle的线程,定时扫描引用队列,发现新加入的虚引用对象,将会执行虚引用对象中的方法,将直接内存进行释放。

终结器引用:
在Object类中存在一个 finallize方法,当子类重写了该方法,在进行垃圾回收时,将会执行 finallize 方法。当对象没有强引用引用对象时,JVM创建终结器引用,垃圾回收时将终结器引用加入引用队列,注意此时没有进行垃圾回收,一个优先级很低的线程FinalizerHandle查看引用队列是否有终结器引用,然后找到终结器引用引用的对象,执行这个对象finallize()方法。然后在下一次垃圾回收时,就会把对象进行垃圾回收。

垃圾回收算法
经过第一步,判断那些对象可以被垃圾回收,在进行回收时,还要有一些垃圾回收算法。

  1. 标记清除
  2. 标记整理
  3. 复制

标记清除:
找到可以被垃圾回收的对象,在内存的起始位置和终止位置,作标记,表示已将对象清除。

第一步,通过GC root将可以回收的对象找到。
请添加图片描述
第二步,将可以回收的对象,作标记
请添加图片描述
第三步,将对象所占内存清除。所谓清除,并不是将对象所占内存,进行删除,而是将对象所占内存空间标记为空闲空间,以便在下一次,将空间分配给新的对象。
请添加图片描述
标记清除算法的优点,速度快,只需要将对象所占的内存空间标记为空闲空间即可,不需要额外处理,缺点,容易产生内存碎片。

标记整理:
第一步,找出可以回收的对象。
请添加图片描述第二步,进行内存整理,将不会被回收的对象,合并到一块,避免存在内存碎片。
请添加图片描述
标记整理的优点是内存中不会存在碎片,缺点是由于需要内存的整理,速度会比较慢。

复制算法:
将内存中的区域,分为两块大小相等的区域。分别为 From,To 。
如图:
在这里插入图片描述
第一步,将可以回收的对象标记出来。
请添加图片描述
第二步:
将from区域中的不会被垃圾回收的对象,依次复制到 To 区域,将From区域的内存清空请添加图片描述
第三步:将From和To互换。
请添加图片描述
复制算法的优点是不会产生内存碎片,缺点是,需要使用双倍的内存空间。

在JVM中根据不同的情况,选择不同的垃圾回收算法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值