JVM-垃圾回收(1)
如何判断对象是否可以回收
引用计数法
只要这个对象被引用则让其计数+1,当没有引用该对象时,即计数为0的时候,该对象就会作为垃圾被回收。
弊端:循环引用
当两个以上的对象相互引用,形成闭环的时候,导致它们的计数无法归零无法被垃圾回收!
可达性分析算法
在垃圾回收之前,对堆内存中的所有对象进行一遍扫描(沿着 GC Root对象 为起点的引用链找),
检查是否有对象被根对象直接或间接的引用,如果有,则这些对象不能作为垃圾被回收。
根对象:不能作为垃圾回收的对象。
哪些对象可以作为GC Root对象:
- 系统类 System Class
- 调用操作系统本地方法的类 Native Stack
- 加了锁的对象 Busy Monitor
- 活动线程 Thread
详细可使用Eclipse提供的Memory Analyzer(MAT)工具
五种引用
无论是通过引用计算算法判断对象的引用数量,还是通过可达性分析算法判断对象是否可达,判定对象是否可被回收都与引用有关。
1. 强引用
我们通过new来创建一个新对象的方式是强引用
Object obj = new Object();
2. 软引用
被软引用关联的对象只有在内存不够的情况下才会被回收。
使用 SoftReference 类来创建软引用
SoftReference<Object> sf = new SoftReference<Object>(new Object());
3. 弱引用
被弱引用关联的对象一定会被回收,它只能存活到下一次垃圾回收发生之前。
使用 WeakReference 类来实现弱引用。
WeakReference<Object> wf = new WeakReference<Object>(new Object());
4. 虚引用
一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用取得一个对象。
为一个对象设置虚引用关联的目的是让这个对象在被回收时能让我们收到一个系统通知
使用 PhantomReference 来实现虚引用。
PhantomReference<Object> pf = new PhantomReference<Object>(new Object());
5. 终结器引用
所有对象都继承自Object,其中有finallize()方法,
当没有强引用时,由虚拟机来创建对应的终结器引用。
由垃圾收集器Finalizer线程通过终结器引用找到被引用对象并调用它的finalize()方法,在第二次垃圾回收时才能回收被引用对象
回收算法
标记清除
将不进行回收的对象进行标记,然后清理掉未被标记的对象。
缺点:
- 标记和清除过程效率都不高;
- 会产生大量不连续的内存碎片,导致无法给大对象分配内存。
标记整理
让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。
目的是让内存更加紧凑,解决内存碎片问题
缺点:
- 涉及内存的移动,效率较低
复制
将内存划分为大小相等的两块,每次只使用其中一块,
当这一块内存用完了就将还存活的对象复制到另一块上面,
然后再把使用过的内存空间进行一次清理。
缺点:
- 会使用双倍的内存空间
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)