垃圾收集-判断对象的生死

简介: 垃圾收集-判断对象的生死


什么时候回收对象?当然是这个对象再也不会被用到的时候回收。所以要想解决 “什么时候回收?” 这个问题,我们要先能判断一个对象什么时候什么时候真正的 “死” 掉了,判断对象是否可用主要有以下两种方法。

判断对象是否可用的算法

引用计数算法

算法描述

给对象添加一个引用计数器,每有一个地方引用它,计数器加 1。引用失效时,计数器减 1。计数器值为 0 的对象不再可用。

缺点

很难解决循环引用的问题。即 objA.instance = objB; objB.instance = objA;,objA 和 objB 都不会再被访问后,它们仍然相互引用着对方,所以它们的引用计数器不为 0,将永远不能被判为不可用。

可达性分析算法(主流)

算法描述

从 “GC Root” 对象(根对象)作为起点开始向下搜索,走过的路径称为引用链(Reference Chain),从 “GC Root” 开始,不可达的对象被判为不可用。

Java 中可作为 “GC Root” 的对象:

  • 栈中(本地变量表中的 reference)
  • 虚拟机栈中,栈帧中的本地变量表引用的对象;
  • 本地方法栈中,JNI 引用的对象(native方法);
  • 方法区中
  • 类的静态属性引用的对象;
  • 常量引用的对象;

即便如此,一个对象也不是一旦被判为不可达,就立即死去的,宣告一个的死亡需要经过两次标记过程。

四种引用类型

JDK 1.2 后,Java 中才有了后 3 种引用的实现。

  • 强引用:Object obj = new Object() 这种,只要强引用还存在,垃圾收集器就永远不会回收掉被引用的对象。
  • 软引用: 用来引用还存在但非必须的对象。对于软引用对象,在 OOM 前,虚拟机会把这些对象列入回收范围中进行第二次回收,如果这次回收后,内存还是不够用,就 OOM。实现类:SoftReference
  • 弱引用: 被弱引用引用的对象只能生存到下一次垃圾收集前,一旦发生垃圾收集,被弱引用所引用的对象就会被清掉。实现类:WeakReference
  • 虚引用: 幽灵引用,对对象没有半毛钱影响,甚至不能用来取得一个对象的实例。它唯一的用途就是:当被一个虚引用引用的对象被回收时,系统会收到这个对象被回收了的通知。实现类:PhantomReference

宣告对象死亡的两次标记过程

当发现对象不可达后,该对象被第一次标记,并进行是否有必要执行 finalize() 方法的判断;

  • 不需要执行:对象没有覆盖 finalize() 方法,或者 finalize() 方法已被执行过(finalize() 只被执行一次);
  • 需要执行:将该对象放置在一个队列中,稍后由一个虚拟机自动创建的低优先级线程执行。

finalize() 方法是对象逃脱死亡的最后一次机会,不过虚拟机不保证等待 finalize() 方法执行结束,也就是说,虚拟机只触发 finalize() 方法的执行,如果这个方法要执行超久,那么虚拟机并不等待它执行结束,所以最好不要用这个方法。

finalize() 方法能做的,try-finally 都能做,所以忘了这个方法吧!

方法区的回收

永久代的 GC 主要回收:废弃常量无用的类

  • 废弃常量:例如一个字符串 “abc”,当没有任何引用指向 “abc” 时,它就是废弃常量了。
  • 无用的类:同时满足以下 3 个条件的类。
  • 该类的所有实例已被回收,Java 堆中不存在该类的任何实例;
  • 加载该类的 Classloader 已被回收;
  • 该类的 Class 对象没有被任何地方引用,即无法在任何地方通过反射访问该类的方法。
相关文章
|
7月前
|
Java 程序员
【JVM】强软弱虚引用详细解释
【JVM】强软弱虚引用详细解释
|
2月前
|
Java 测试技术 Android开发
让星星⭐月亮告诉你,强软弱虚引用类型对象在内存足够和内存不足的情况下,面对System.gc()时,被回收情况如何?
本文介绍了Java中四种引用类型(强引用、软引用、弱引用、虚引用)的特点及行为,并通过示例代码展示了在内存充足和不足情况下这些引用类型的不同表现。文中提供了详细的测试方法和步骤,帮助理解不同引用类型在垃圾回收机制中的作用。测试环境为Eclipse + JDK1.8,需配置JVM运行参数以限制内存使用。
38 2
|
5月前
|
存储 缓存 算法
(五)JVM成神路之对象内存布局、分配过程、从生至死历程、强弱软虚引用全面剖析
在上篇文章中曾详细谈到了JVM的内存区域,其中也曾提及了:Java程序运行过程中,绝大部分创建的对象都会被分配在堆空间内。而本篇文章则会站在对象实例的角度,阐述一个Java对象从生到死的历程、Java对象在内存中的布局以及对象引用类型。
140 8
|
7月前
|
存储 编译器 C语言
C陷阱:数组越界遍历,不报错却出现死循环?从内存解析角度看数组与局部变量之“爱恨纠葛”
在代码练习中,通常会避免数组越界访问,但如果运行了这样的代码,可能会导致未定义行为,例如死循环。当循环遍历数组时,如果下标超出数组长度,程序可能会持续停留在循环体内。这种情况的发生与数组和局部变量(如循环变量)在内存中的布局有关。在某些编译器和环境下,数组和局部变量可能在栈上相邻存储,数组越界访问可能会修改到循环变量的值,导致循环条件始终满足,从而形成死循环。理解这种情况有助于我们更好地理解和预防这类编程错误。
168 0
|
存储 缓存 算法
13-大厂面试题:为什么要垃圾回收以及如何判断对象可以回收
接下来我们正式进入第二个系列,关于垃圾回收以及优化。
113 0
13-大厂面试题:为什么要垃圾回收以及如何判断对象可以回收
|
7月前
|
缓存 算法 JavaScript
提高Java程序性能!了解可达性分析算法、强软弱虚引用和三色标记GC的过程,避免不可达对象阻碍程序性能!
提高Java程序性能!了解可达性分析算法、强软弱虚引用和三色标记GC的过程,避免不可达对象阻碍程序性能!
148 0
|
缓存 算法 Oracle
面试官:JVM是如何判定对象已死的?学JVM必会的知识!
作为一名Java程序员,我们每天都在程序里不停地去new对象,但是你知道这些被new出来的对象,最后是怎么被回收的吗?
22248 4
面试官:JVM是如何判定对象已死的?学JVM必会的知识!
|
算法 安全 Java
JVM学习日志(十一) 对象进入老年代的情况 及 空间担保机制
对象进入老年代的情况 及 空间担保机制 简述
425 0
JVM学习日志(十一) 对象进入老年代的情况 及 空间担保机制
|
缓存 算法 Java
JVM学习日志(七) 如何判断对象可以回收可达性分析算法
如何判断对象可以回收可达性分析算法 简述
137 0
JVM学习日志(七) 如何判断对象可以回收可达性分析算法
|
缓存 算法 JavaScript
还有程序员搞不懂JVM垃圾回收器并发标记清除回收的内存管理?
JVM中从JDK 4正式引入并发回收,用于解决垃圾回收过程中停顿时间过长的问题。JVM的垃圾回收器通常采用分代设计,新生代和老生代采用不同的垃圾回收算法,在并发垃圾回收器中,新生代采用并行的复制算法,老生代采用并发的标记清除算法