对象存活与引用

本文围绕Java中对象存活判定及引用类型展开。垃圾收集器回收对象前需确定其是否存活,介绍了引用计数法和可达性分析法,指出JVM未采用引用计数法。还阐述了强引用、软引用、弱引用和虚引用四种引用类型及其特点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

垃圾收集器在对对象进行回收前,第一件事就是要确定对象是否存活

1.引用计数法

  • 给对象添加一个引用计数器,每当有一个地方引用它时,计数器就增加1;引用失效时,计数器就减1。

  •  任何时刻计数器为0的对象就是不可能被使用的

引用计数法实现简单,判定效率较高,但无法解决对象之间的相互引用问题,JVM并没有采用这种方法。 

代码测试

package basicKnowledge.jvm.GC;

/**
 * @program:summary
 * @author:peicc
 * @create:2019-07-15 16:50:15
 **/
//引用计数法判断对象是否存活
public class IsAlive {
    private Object instance=null;
    private static final int  _1MB=1024*1024;
    private byte[]bigsize=new byte[2*_1MB];
    public static void main(String[] args) {
        IsAlive objectA=new IsAlive();
        IsAlive objectB=new IsAlive();
        objectA.instance=objectB;//相互引用
        objectB.instance=objectA;//相互引用
        objectA=null;
        objectB=null;
        System.gc();
    }
}

对象objectA与对象objectB通过字段instance相互引用,除此之外,这两个对象再无引用,实际上这两个对象已经不可能再被访问 。但由于它们相互引用着对方,导致它们的引用计数都不为0,于是通过引用计数法无法再通知GC收集器回收它们

运行结果

"C:\Program Files\Java\jdk1.8.0_191\bin\java.exe" -verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+UseParNewGC -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=15 "basicKnowledge.jvm.GC.IsAlive
[Full GC (System.gc()) [Tenured: 0K->627K(10240K), 0.0354981 secs] 6110K->627K(19456K), [Metaspace: 3209K->3209K(1056768K)], 0.0364469 secs] [Times: user=0.00 sys=0.00, real=0.04 secs] 
Heap
 par new generation   total 9216K, used 82K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
  eden space 8192K,   1% used [0x00000000fec00000, 0x00000000fec14920, 0x00000000ff400000)
  from space 1024K,   0% used [0x00000000ff400000, 0x00000000ff400000, 0x00000000ff500000)
  to   space 1024K,   0% used [0x00000000ff500000, 0x00000000ff500000, 0x00000000ff600000)
 tenured generation   total 10240K, used 627K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
   the space 10240K,   6% used [0x00000000ff600000, 0x00000000ff69cf48, 0x00000000ff69d000, 0x0000000100000000)
 Metaspace       used 3216K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 349K, capacity 388K, committed 512K, reserved 1048576K
Java HotSpot(TM) 64-Bit Server VM warning: Using the ParNew young collector with the Serial old collector is deprecated and will likely be removed in a future release

Process finished with exit code 0

 从运行结果可以看出,GC日志从6110K->627K,说明虚拟机并没有因为两个对象相互引用就没有回收它们。也说明了JVM没有采用引用计数法来判定对象是否存活

2. 可达性分析法

通过一些列被称为“GC Roots”的对象作为起始点,从这些根节点向下搜索,走过的路径称为引用链,当一个对象到达GC Roots没有任何引用链时,该对象则是不可用的。

 

Java语言中,可以作为GC Roots的对象有 :

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

3.引用类型

如果reference类型的数据中存储的数值代表另一块内存的起始地址,就称这块内存代表着一个引用

  • 强引用:

  • 类似Objecct  object=new Object();只要强引用存在,该对象永远不会被回收
  • 软引用:

  • 用来描述一些有用但非必需的的对象
  • 在发生内存溢出之前,这些对象将会被进行第二次回收。如果这次回收还没有足够的内存,才会抛出内存溢出异常
  • SoftReference类来实现软引用
  • 弱引用:

  • 用来描述非必须对象
  • 被弱引用关联的对象智只能生存到下一次垃圾收集发生之前(无论内存是否够用)
  • WeakReference类来实现弱引用
  • 虚引用

  • 无法通过虚引用获取一个对象的实例
  • 为一个对象设置虚引用关联的唯一目的就是能在这个对象被收集器收集时收到一个系统通知
  • PtantomReference类来实现虚引用

 注:本文所有内容均来自《深入理解Java虚拟机》

### Java 垃圾回收中标记存活对象的方法 在Java虚拟机(JVM)中,垃圾回收器通过特定的算法来区分哪些对象是活动的(即仍被引用),哪些是可以回收的。对于标记存活对象的过程,主要依赖于可达性分析算法[^3]。 #### 可达性分析算法原理 该算法从一系列称为“GC Roots”的根节点集合出发,按照图论中的连通理论遍历整个对象图结构。只要是从这些根节点开始能够到达的对象都被认为是活跃状态;反之,则会被视为可回收对象。典型的GC Roots成员包括但不限于: - 正在执行方法中的局部变量表内的引用; - 所有类静态属性所持有的引用; - 运行时常量池里的引用; - 本地方法栈中JNI(Native方法)持有者们的引用。 一旦确定了GC Roots之后,JVM会采用不同的策略去追踪并标记那些可以从这些起点访问到的对象。这一步骤通常发生在所谓的“Stop The World”事件期间,在此过程中应用程序的所有线程都会暂时停止以便让GC安全地完成其工作而不受干扰[^4]。 #### 实际操作过程 当触发一次完整的垃圾收集周期时,具体的操作流程如下所示: 1. **初始化阶段**:准备必要的数据结构用于记录已扫描过的对象以及待处理队列。 2. **标记阶段**:从GC Roots开始递归地标记每一个可以直接或间接触及的目标实例,并将其加入到已知存活列表里。 3. **清理阶段**:依据前面两个步骤的结果决定哪些区域应该释放给后续分配新对象使用。 ```java // 示例代码展示了一个简单的模拟场景,其中包含了创建对象和显式调用System.gc() class TestGC { public static void main(String[] args) throws InterruptedException { Object objA = new Object(); Object objB = new Object(); // 创建一些临时对象供测试用 for (int i = 0; i < 10000; ++i) { new Object(); } Thread.sleep(500); // 给予足够的时间使上述短生命周期对象成为候选回收目标 System.gc(); // 请求进行垃圾回收 } } ``` 这段程序展示了如何利用`System.gc()`建议启动一次全局范围内的垃圾搜集动作,尽管实际效果取决于当前使用的垃圾收集器配置及其内部逻辑实现[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值