JVM系列(三)如何判断对象可以被回收

我们知道JVM的垃圾回收主要集中在堆内存上,当新生代和老年代空间不足时都会发生GC,那么具体有什么区别和具体可以回收哪些对象呢?下面我们一起来探讨一下。


Minor GC/Young GC: 又称新生代GC,指发生在新生代的垃圾收集动作;因为Java对象大多是朝生夕灭,所以Minor GC非常频繁,一般回收速度也比较快;
Major GC/Full GC: 指发生在老年代的GC;
出现Full GC经常会伴随至少一次的Minor GC(不是绝对,Parallel Sacvenge收集器就可以选择设置Major GC策略);Major GC速度一般比Minor GC慢10倍以上;Full GC会回收新生代和老年代的垃圾

下面我们再来讨论一下垃圾回收时怎么判断哪些对象可以被回收,在讨论这个问题之前,我们先来了解一下在java中的常见的四种引用

一、强引用

强引用是使用最普遍的引用。如果一个对象具有强引用,那垃圾回收器绝不会回收它。如下:
Object o=new Object(); // 强引用
当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足的问题。如果不使用时,要通过如下方式来弱化引用,如下:
o=null; // 帮助垃圾收集器回收此对象
显式地设置o为null,或超出对象的生命周期范围,则gc认为该对象不存在引用,这时就可以回收这个对象。具体什么时候收集这要取决于gc的算法

二、软引用

如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存。
String str = new String(“abc”); // 强引用
SoftReference softRef = new SoftReference(str); // 软引用

三、弱引用

只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。
String str=new String(“abc”);
WeakReference abcWeakRef = new WeakReference(str);

四、虚引用

“虚引用”顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。

在这里插入图片描述
下面我们来具体说明一下,jvm进行垃圾回收时,如何判断哪些对象可以被回收那些对象不可以被回收。判断对象是否可以被回收主要有两种方式:1.引用计数法 2.可达性分析算法。但是一般虚拟机(HotSpot)都会采用可达性分析算法。具体两者有什么区别呢?

·引用计数法(feference-countint) : 每个对象有一个引用计数器,当对象被引用一次则计数器就加1,当对象引用失效一次则计数器减1,对于计数器为0的对象就意味着可以被回收。

·可达性分析算法(GC Root Tracing) : 从GC Roots 作为起点开始搜索,能和GC Roots根直接相连的对象都被标记为非垃圾对象,其余未标记的都是垃圾对象。

哪些对象可以作为GC Roots根节点: 栈的本地变量表所引用的对象、方法区的静态变量和常量所引用的对象、本地方法栈中所引用的对象。

下面我们结合代码和具体的内存分配情况具体说明为什么虚拟机一般使用可达性分析算法而不使用引用计数法。

public class GcTrace {
    public static void main(String[] args) {
    	// step 1
        GcObject obj1 = new GcObject();
        // step 2
        GcObject obj2 = new GcObject();

		// step 3
        obj1.instance = obj2;
        // step 4
        obj2.instance = obj1;
		// step 5
        obj1 = null;
        // step 6
        obj2 = null;
    }
}

public class GcObject {
    public Object instance = null;
}

假设使用引用计数法进行分析;
以上代码分为六个步骤执行:
1: 执行完第一、二步后,obj1和obj2对象的引用计数器的值都为1;
2: 当执行完第三、四步骤后,obj1和obj2对象的引用计数器的值又分别加1,此时都为2;
3: 当执行完第五、六步骤后,obj1和obj2对象的引用计数器的值又分别减1,此时为1。
在进行垃圾回收时,判断对象的应用计数值不为0,所以此对象不会被回收。所以当对象存在循环引用的情况是,使用引用计数法不能将对象进行回收,就有可能造成内存溢出问题。

假设使用可达性分析算法进行分析;
同样代码分为六个步骤执行:
对照下面的内存模型,当六步都执行完成后,内存分配情况如下图所示:栈中指向堆内存的指针已经断开,只有在堆内存中存在相互引用的指针。
那么此时进行垃圾回收,虽然堆内存中对象存在相互引用,但是他并不和GC Roots根直接相连,所以是可以被回收掉的。回顾一下上面讲的可以作为GC Roots根的对象(栈的本地变量表所引用的对象、方法区的静态变量和常量所引用的对象、本地方法栈中所引用的对象)
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Java虚拟机中,判断一个对象是否可以回收的方法是通过垃圾收集器对内存空间的扫描。如果发现一个对象没有被任何指针或者引用所指向,也没有被任何活动线程所持有,那么这个对象就可以被回收Java虚拟机还提供了一种判断方式,叫做“可达性分析”。可达性分析的基本思想就是通过一系列称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为“引用链”,当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的。 ### 回答2: JVM判断一个对象是否可以回收主要依靠垃圾回收算法和GC Root对象。以下是判断对象是否可以回收的几个条件: 1. 引用计数法(Reference Counting):每当一个对象被引用时,引用计数加1,引用失效时计数减1。当计数器为0时,说明该对象没有任何引用,可以判断为可回收对象。然而,该算法难以解决循环引用的问题,即对象之间相互引用形成闭环,导致计数始终不为0。 2. 可达性分析算法(Reachability Analysis):JVM通过可达性分析算法,以GC Root对象作为起始点,沿着对象之间的引用链进行遍历,若某个对象与GC Root对象不能形成引用链,则判断对象为不可达对象,即可以回收。 GC Root对象包括: - 虚拟机栈中的引用:局部变量表中的引用对象 - 方法区静态属性引用的对象:类的静态变量 - 方法区常量引用的对象:字符串常量等 - 本地方法栈中的JNI引用:Java Native Interface引用的对象 3. 垃圾回收算法:JVM采用不同的垃圾回收算法来标记和回收回收对象。常见的算法有标记清除算法(Mark and Sweep)、复制算法(Copying)、标记整理算法(Mark and Compact)等。这些算法会定期执行,对堆中的对象进行标记和回收判断对象是否可以回收的依据是对象是否被标记为可达状态。 综上所述,JVM判断对象是否可以回收主要依靠垃圾回收算法和GC Root对象的可达性分析。当一个对象不再被引用或与GC Root对象没有引用链相连时,可以被判断为可回收对象,并由垃圾回收器对其进行回收。 ### 回答3: JVM判断一个对象是否可以回收主要依赖两种垃圾回收算法:引用计数算法和可达性分析算法。 1. 引用计数算法:引用计数算法是通过为每个对象维护一个引用计数器来判断对象的引用数量。当对象被创建时,引用计数器初始化为1,当有新的引用指向对象时,引用计数器加1;当引用失效或超出作用域时,引用计数器减1。当引用计数器为0时,表示对象不再被引用,可以判定为可回收对象。 然而,引用计数算法不能解决循环引用的问题。当两个或多个对象互相引用时,它们的引用计数器都无法达到0,即使它们已经不再被程序使用,也不会被回收。 2. 可达性分析算法:可达性分析算法是JVM中主要采用的垃圾回收算法,通过判断对象是否可被一组称为"GC Roots"的对象直接或间接引用来进行标记和回收。 在JVM中,GC Roots包括: - 当前执行方法中的局部变量和输入参数所引用的对象 - 活动线程所引用的对象 - 静态变量所引用的对象 - JNI引用变量所引用的对象 GC Roots会被作为起始点,遍历对象引用关系图,将所有可达的对象标记为可达对象,而未被标记的对象即为不可达对象,也就是可回收对象。可达性分析算法能够解决循环引用的问题,因为循环引用的对象都不会被GC Roots直接或间接引用,将被判定为不可达对象。 当垃圾回收器运行时,会清除所有不可达的对象,释放其占用的内存空间。这样就判定了一个对象是否可以回收
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值