根搜索算法(JVM垃圾回收对象判定标准)

1.根搜索算法

又叫可达性算法。在主流的商用程序语言中(Java和C#),都是使用根搜索算法判定对象是否存活 的。
基本思路就是通过一系列的名为“GCRoot”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GCRoot没有任何引用链相连(就 是从GCRoot到这个对象不可达)时,则证明此对象是不可用的。
不可达不一定会被回收, 可以用finalize()方法抢救下, 但不推荐。
GC Roots中的对象是指在内存中仍然存在且可访问的对象。

在这里插入图片描述

GC Roots包括以下几种类型的对象:

  1. 虚拟机栈(栈帧中的本地变量表)中引用的对象。
虚拟机栈中的栈帧中的本地变量表存储了方法执行过程中的局部变量和参数。
在Java虚拟机中,本地变量表中存储的是基本数据类型和对象引用。
对于引用类型(对象类型),本地变量表中存储的是对象的引用,而不是对象本身。 
 
当一个方法被调用时,会创建一个新的栈帧,其中会包含本地变量表。
本地变量表中存储了方法中使用的局部变量和参数,包括对对象的引用。这些引用指向堆内存中实际的对象。 
 
例如,对于以下代码片段:
java
public class MyClass {
    public void myMethod() {
        String str = "Hello";
        System.out.println(str);
    }
}
在 myMethod 方法执行时,本地变量表中会存储一个对字符串对象"Hello"的引用。
这个引用指向堆内存中存储的实际字符串对象。
所以,虚拟机栈中的栈帧中的本地变量表中的引用的对象指的是**存储在堆内存中的实际对象**,
而本地变量表中存储的是对这些对象的引用。

简单来说就是创建对象后,这个对象所存储的真正地址会被清除

  1. 方法区中类静态属性引用的对象。
方法区中的类静态属性引用的对象是指类加载时在方法区中存储的静态属性所引用的对象。
在Java中,当一个类被加载到内存中时,其中的静态属性会被存储在方法区中,并且这些静态属性可以引用其他对象。

例如,如果一个类中有一个静态属性如下:
public class MyClass {
    public static String staticString = "Hello";
}
在类加载时,静态属性 `staticString` 会被存储在方法区中,并且它引用了一个字符串对象"Hello"。
这样,方法区中的类静态属性引用的对象就是这个字符串对象。

需要注意的是,方法区是Java虚拟机规范中定义的内存区域,用于存储类的结构信息、静态变量、常量等。
  1. 本地方法栈中JNI引用的对象。
本地方法栈中JNIJava Native Interface)的引用对象是指在Java应用程序中调用本地方法时,
JNI桥接层中涉及的引用对象。JNI允许Java应用程序调用本地(非Java)代码,
这些本地代码通常是用CC++等语言编写的。

在JNI中,Java对象在本地方法栈中被表示为jobject类型的引用。这些引用对象是JNI提供的机制,
用于在Java对象和本地代码之间进行交互。通过JNI的函数调用,Java对象可以在本地方法中被引用和操作。

例如,在JNI中可以通过 `GetObjectField` 函数获取Java对象的字段值,并且返回一个jobject类型的引用对象。
这个引用对象可以在本地方法中被使用,以实现Java对象和本地代码之间的数据传递和操作。

总之,本地方法栈中JNI的引用对象是指JNI桥接层中用于表示Java对象的引用,以便在本地方法中访问和操作Java对象。
  1. 常量引用的对象(final)。
方法区中的常量引用的对象是指在类加载时,存储在方法区中的常量池中的常量所引用的对象。
在Java中,常量池是方法区的一部分,用于存储类中的常量、字符串字面值和符号引用等信息。

常量池中的常量可以是基本类型的常量,也可以是字符串常量、类常量、方法句柄、方法类型等。
这些常量在类加载时被加载到方法区的常量池中,并且可以被类中的其他部分引用。

例如,对于以下代码片段:
public class MyClass {
    public static final int NUM = 10;
    public static final String STR = "Hello";
}
在类加载时,常量 `NUM` 和 `STR` 会被存储在方法区的常量池中,分别引用整数常量10和字符串常量"Hello"。
因此,方法区中的常量引用的对象就是这些常量所对应的值。

这些对象被认为是程序中仍然活跃的对象,因此它们不会被垃圾回收器回收。其他没有被GC Roots直接或间接引用到的对象将被认为是不可达的,可能会被垃圾回收器回收。

注:
在Java中,静态类不是GC Roots。GC Roots是指能直接或间接引用到对象的地方,从而防止对象被垃圾回收器回收。静态类本身并不直接持有对象的引用,因此静态类本身不会成为GC Roots。 但静态类中的静态属性引用的对象可能会成为GC Roots的一部分。

Java中,静态类这个概念并不存在。类可以被声明为静态内部类,但类本身并不是静态的。
静态内部类是指在另一个类内部定义的静态类,它可以独立存在而不依赖于外部类的实例。
静态内部类可以通过外部类的类名直接访问,不需要先创建外部类的实例。

以下是一个静态内部类的示例:
public class OuterClass {
    private static int outerStaticVar = 10;
    
    static class StaticInnerClass {
        private int innerVar;

        public StaticInnerClass(int innerVar) {
            this.innerVar = innerVar;
        }

        public void display() {
            System.out.println("Outer static variable: " + outerStaticVar);
            System.out.println("Inner variable: " + innerVar);
        }
    }
    
    public static void main(String[] args) {
        OuterClass.StaticInnerClass inner = new OuterClass.StaticInnerClass(20);
        inner.display();
    }
}
在上面的示例中, `StaticInnerClass` 是一个静态内部类,它可以直接通过 `OuterClass.StaticInnerClass` 
来访问。静态内部类通常用于将与外部类相关联的类逻辑上组织在一起。

2.引用计数法

给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加1:当引用失效时,计数器值 就减1:任何时刻计数器都为0的对象就是不可能再被使用的。

优点 :
实现简单,判断效率高,大部分情况下都是很不错的算法
缺点:
Java语言中没有选用引用计数算法来管理内存,其中最主要的原因是它很难解决对象之间的相互循环 引用的问题。

public class Test { 
     public static void main(String[] args) {

        MyObject object1 = new MyObject(); 
        MyObject object2 = new MyObject();

        object1.object = object2; 
        object2.object = object1;

        object1 = null; 
        object2 = null;

    }
}

class MyObject{ 
     MyObject object;
}

  • 9
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值