java对象强、软、弱、虚四种引用

介绍

java垃圾回收机制通过两种方法来判断对象是否回收,分别是引用计数法可达性分析算法

java在jdk1.2之前,只存在一种引用,当对象只有被引用时才会存在,当没有引用时,引用计数为0,对象就会被垃圾回收判断为失效,进行回收

java在jdk1.2开始,对象的引用分为4种,分别是强引用>软引用>弱引用>虚引用,程序员可以通过不同的引用控制对象的生命周期,方便垃圾回收,使程序更加灵活的控制对象生命周期

在这里插入图片描述
java在jdk1.2开始,在java.lang.ref提供了一个抽象类Reference和三个实现类SoftReference(软引用)、WeakReference(弱引用)、PhantomReference(虚引用

强引用

/**
     * 强引用
     */
    public void testStrongReference(){
    
    
        //强引用
        Object obj=new Object();
    }

业务代码中的对象,绝大部分都是强引用,比如Object obj=new Object(),这种引用的对象绝对不会被垃圾回收,当内存不足以分配创建对象的内存时,Java虚拟机会抛出OOM错误,使程序异常终止,也不回收这种对象,只有这个引用消失后(* 显式赋值为null*,方法生命周期结束等),引用计数为0,才会被垃圾回收

软引用

/**
     * 软引用
     */
    public void testSoftReference(){
    
    
        //强引用
        Object obj=new Object();
        //放入SoftReference
        SoftReference<Object> softReference = new SoftReference<Object>(obj);
        System.out.println( softReference.get());//java.lang.Object@39a054a5
    }

软引用要比强引用低一个等级,用来表示有用非必要的对象,只有当内存不足的时候,才会对软引用对象进行垃圾回收,可以来实现缓存,不用担心存在内存溢出问题。

/**
     * 软引用(引用队列)
     */
    public void testSoftReferenceQueue(){
    
    
        //引用队列
        ReferenceQueue referenceQueue = new ReferenceQueue<>();

        //使用守护线程
        Thread thread= new Thread(new Runnable() {
    
    
            @Override
            public void run() {
    
    
                try {
    
    
                    int i=0;
                    SoftReference<Integer> softReference;
                    //如果对象被gc回收
                    while((softReference = (SoftReference) referenceQueue.remove()) != null) {
    
    
                        System.out.println("第"+i+"次回收:"+softReference);
                        i++;
                    }
                }catch (Exception e){
    
    

                }
            }
        });
        thread.setDaemon(true);//设置为守护线程,监听对象变化
        thread.start();

        Map<Object, Object> map = new HashMap<>();
        Object obj=new Object();
        for(int i=0;i<2000; i++){
    
    
            //放入SoftReference转为软引用
            byte [] bytes=new byte[1024*1024];
            SoftReference<byte []> softReference = new SoftReference<byte []>(bytes,referenceQueue);
            //将软引用作为key
            map.put(softReference,obj);
        }
    }

第1992次回收:java.lang.ref.SoftReference@7c7a06ec
第1993次回收:java.lang.ref.SoftReference@1d296da
第1994次回收:java.lang.ref.SoftReference@776aec5c
[GC (Allocation Failure) [PSYoungGen: 30K->64K(1536K)] 3833K->3866K(5632K), 0.0002270 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [PSYoungGen: 64K->64K(1536K)] 3866K->3866K(5632K), 0.0002042 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC (Allocation Failure) [PSYoungGen: 64K->0K(1536K)] [ParOldGen: 3802K->3802K(4096K)] 3866K->3802K(5632K), [Metaspace: 3120K->3120K(1056768K)], 0.0019695 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [PSYoungGen: 0K->0K(1536K)] 3802K->3802K(5632K), 0.0002220 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC (Allocation Failure) [PSYoungGen: 0K->0K(1536K)] [ParOldGen: 3802K->730K(4096K)] 3802K->730K(5632K), [Metaspace: 3120K->3120K(1056768K)], 0.0025588 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
第1995次回收:java.lang.ref.SoftReference@408d971b
第1996次回收:java.lang.ref.SoftReference@75d4a5c2
第1997次回收:java.lang.ref.SoftReference@557caf28

软引用通过SoftReference来进行实现,可以将软引用对象注册到引用队列(Referencequeue)中,引用队列来判断对象是否被释放,Reference存在next字段,有四种状态,可以根据状态判断,但next仅在放到queue中才会有意义( 因为,只有在enqueue的时候,会将next设置为下一个要处理的Reference对象 )
在这里插入图片描述
active:内存被分配的时候状态。
pending:即将回收内存,存入关联的引用queue中时的状态。
Enqueued:内存被回收的时候,进入引用队列中的状态。
Inactive:不活跃状态。

弱引用

/**
     * 弱引用
     */
    public void testWeakReference(){
    
    
        //强引用
        Object obj=new Object();
        //放入WeakReference
        WeakReference<Object> weakReference = new WeakReference<Object>(obj);
        System.out.println(weakReference.get());//java.lang.Object@39a054a5
    }

弱引用要比软引用第一个等级,用来表示非必要的对象不管内存是否充足,都会垃圾回收其对象,但是因为垃圾回收线程优先级很低,所以不会很快回收
弱引用通过WeakReference来进行实现,可以将弱引用对象注册到引用队列(Referencequeue)中,引用队列来判断对象是否被释放。小伙伴们如果想测试,可以用上面弱引用的线程监听方法

虚引用

/**
     * 虚引用
     */
    public void testPhantomReference(){
    
    
        //强引用
        Object obj=new Object();
        //必须使用引用队列
        ReferenceQueue referenceQueue = new ReferenceQueue();
        //放入PhantomReference
        PhantomReference<Object> phantomReference = new PhantomReference<Object>(obj,referenceQueue);
        System.out.println(phantomReference.get());//null 因为虚引用无法获取对象实例,只是监听作用
        System.out.println(obj);//java.lang.Object@39a054a5
    }

虚引用
虚引用相较于其他引用,就如形同虚设,无法通过虚引用来获取对象实例,如果一个对象仅仅被虚引用持有,则随时会被垃圾回收,和软引用、弱引用不同,其必须注册到Referencequeue中,当对象即将被回收时,就会将虚引用放入到引用队列中,通过判断虚引用是否加入到引用队列来判断对象是否要被回收

猜你喜欢

转载自blog.csdn.net/qq_38306425/article/details/106685465
今日推荐