java中的引用

在java中,处理基本数据类型意外,任何对象都是引用类型,不同的引用类型主要体现在对象是否可达和对垃圾收集器的影响

java中的引用,可以分类为以下4种类型

  • 强引用
  • 软引用
  • 弱引用
  • 幻象引用(虚引用)

强引用
在日常程序中,我们通常使用=来给对象赋值,向Object obj = new Object();这种对象赋值方式就属于强引用,强引用存在期间(对象可达),当触发GC时,垃圾收集器不会触碰该类引用的对象。及时jvm内存不足,jvm会抛出OutOfMemoryError(内存溢出错误),也不会回收强引用类型的对象。但是需要注意的是,在方法、for循环等有作用域范围的强引用,如

void test(){
Object obj = new Object();
while(flag){
Object obj1 = new Object();
}
}

复制代码

在while中,obj1虽然是强引用类型,但是while结束后,就不可达了,所以obj1在while结束后就可以被gc回收了。
而obj的生命周期在整个test方法中,其引用保存与java栈中,而引用的真正内容保存在java堆中,当方法栈退出后,obj也就不可达了,其可以被GC回收,但是弱把OBJ赋值给一个外部的局部变量,引用又可达了,就不会被gc回收。
说的有点绕哈,就是强引用类型主要是看对象时候可达,若引用不可达,即没有一个对象指向对象的内存地址,那么gc就可以回收该空间。

软引用
前边说到,强引用及时JVM内存不足也不会在GC时回收对象内存空间,是否有一种引用类型,在jvm内存充裕时,引用存在,在内存不足时,gc回收空间呢?答案就是软引用,软引用是对强引用的弱化版。在内存充足时,引用可达,内存不足时候,回收对象地址。在JVM抛出OutOfMemoryError前,会查看堆中是否存在软引用类型的对象,弱存在,则回收该类型引用的空间,弱空间充裕了,就没必要抛出内存溢出的错误了。
软引用使用如下

//我使用了一个RefrenceTest的程序,重写finalize方法来判断gc时候回收
class RefrenceTest{
    @Override
    protected void finalize() throws Throwable {
        System.out.println("finalize----");
    }
}
//main方法如下
public static void main(String[] args) {
        //构架一个强引用类型的数据
        RefrenceTest refrenceTest = new RefrenceTest();

        //构建一个软引用类型的数据
        SoftReference<RefrenceTest> softReference = new SoftReference<>(refrenceTest);//

        //使强引用不可达 就只剩下软引用了
        refrenceTest = null;

        //模拟内存不足的代码

        java.util.List<Object> objectList = new ArrayList<>();
        for (int i=0;i<10000000;i++){
            objectList.add(new Object());
        }
    }

复制代码

当我new了100W个(90W个不回收,具体和jvm内存大小有关)强引用类型的Object对象放与ArrayList中时候,软引用被回收。
同时,软引用可以和引用队列(RefrenceQueue一起使用),当对象被gc前,对象地址会被先放入引用队列中,等待下一次gc回收,使用如下

public static void main(String[] args) {
        //构架一个强引用类型的数据
        RefrenceTest refrenceTest = new RefrenceTest();

        // 引用队列
        ReferenceQueue<RefrenceTest> referenceQueue = new ReferenceQueue<>();
        //构建一个软引用类型的数据
        SoftReference<RefrenceTest> softReference = new SoftReference<>(refrenceTest,referenceQueue);//

        //使强引用不可达 就只剩下软引用了
        refrenceTest = null;
        
        //模拟内存不足的代码
        java.util.List<Object> objectList = new ArrayList<>();
        for (int i=0;i<1000000;i++){
            objectList.add(new Object());
        }

    }
复制代码

弱引用
前边说到,软引用类型在gc时会考虑内存是否足够以确定要不要回收,而弱引用则是在gc时不用考虑内存是否足够,当gc时扫描到弱引用对象时候,会立刻回收

public static void main(String[] args) {
        //构架一个强引用类型的数据
        RefrenceTest refrenceTest = new RefrenceTest();


        //构建一个软引用类型的数据
        WeakReference<RefrenceTest> softReference = new WeakReference<>(refrenceTest);

        //使强引用不可达 就只剩下弱引用了
        refrenceTest = null;

        //手动触发gc
        System.gc();


    }

复制代码

对于弱引用,也可以使用引用队列,当gc扫描到弱引用类型数据时候,会将地址放入引用队列中,等待下一次gc回收。

public static void main(String[] args) {
        //构架一个强引用类型的数据
        RefrenceTest refrenceTest = new RefrenceTest();

        //引用队列
        ReferenceQueue<RefrenceTest> referenceQueue = new ReferenceQueue<>();
        //构建一个软引用类型的数据
        WeakReference<RefrenceTest> softReference = new WeakReference<>(refrenceTest,referenceQueue);

        //使强引用不可达 就只剩下弱引用了
        refrenceTest = null;

        //手动触发gc
        System.gc();

        System.out.println(softReference.get());//null
        System.out.println(referenceQueue.poll());//输出Refrence内存地址

    }

复制代码

幻象引用(虚引用)
幻象引用是4中引用中最特殊的一种类型,其规定在构造方法中必须增加引用队列若一个对象只有幻象引用,则他和没有引用一样,在任何时候都会被gc回收。而触发gc时候,就会将地址添加到引用队列中,因此,使用幻象引用,可以来判断对象是否即将被GC回收,Cleaner机制就是用到来幻象引用(挖个坑,下次说Cleaner机制),使用方法:

//引用队列
        ReferenceQueue<RefrenceTest> referenceQueue = new ReferenceQueue<>();
        //构建一个幻象引用类型的数据
        PhantomReference<RefrenceTest> phantomReference
                = new PhantomReference<>(new RefrenceTest(),referenceQueue);
复制代码

最后,文章中可能有错误,我水平有限(还是个学生(^-^))欢迎大致指正学习。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享