java-引用

img

img

概述

引用概括起来就是 强软弱虚
了解Java中的软引用、弱引用、虚引用的适用场景以及释放机制

  • 强引用是我们 new 出来生成的那种,生命周期跟随着垃圾回收器
  • 软引用(SoftReference) , 当内存不足的时候就会给回收, 具体的回收的条件有两个:(1)距离上次gc后首次调用的时间间隙 (2)JVM堆大小是否快到上次使用的大小容量了
  • 弱引用 (WeakReference) ,场景例如: ThreadLocal , 无论如何都会回收 ,底层原理是该引用会断开对象的指针,即是使 引用为 null (都为null 了, 下次gc 肯定就会被回收了)
  • 虚引用 (PhantomReference) ,场景例如: DirectByteBuffer , 没实际意义, 虚引用并不会决定对象的生命周期。主要用来跟踪对象被垃圾回收器回收的活动。

问题

  • 都说软引用 (SoftReference) 在内存不足的时候就会回收 , 那么什么时候叫内存不足呢?
  • ThreadLocal 里使用了 weakReference , 这是为什么

源码分析

引用回收流程

img

源码分析

public abstract class Reference<T> {


    //                        第一部分
    //===================================================
    //引用的对象
    private T referent;        
    //===================================================


    //                        第二部分
    //===================================================
	//回收队列,由使用者在Reference的构造函数中指定
    volatile ReferenceQueue<? super T> queue;
 	//当该引用被加入到queue中的时候,该字段被设置为queue中的下一个元素,以形成链表结构
    volatile Reference next;
    //在GC时,JVM底层会维护一个叫DiscoveredList的链表,存放的是Reference对象,discovered字段指向的就是链表中的下一个元素,由JVM设置
    transient private Reference<T> discovered;  
	//等待加入queue的Reference对象,在GC时由JVM设置,会有一个java层的线程(ReferenceHandler)源源不断的从pending中提取元素加入到queue
    private static Reference<Object> pending = null;
    //===================================================


    //                        第三部分
    //===================================================
	//进行线程同步的锁对象
    static private class Lock { }
    private static Lock lock = new Lock();
    //===================================================




}

强引用

Object o = new Object();

软引用(SoftReference)

弱引用 (WeakReference)

ThreadLocal

img

ThreadLocal 底层是使用了 Thread 对象的内部静态类ThreadLocalMap来存储键值对的, 而 ThreadLocalMap 的键值对对象可以看到是继承自 WeakReference

// java.lang.ThreadLocal#get
public T get() {
        // 获取到线程
        Thread t = Thread.currentThread();
        // 其实就是对 Thread 的变量 ThreadLocalMap , 进行操作 
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
}

//java.lang.ThreadLocal#getMap
ThreadLocalMap getMap(Thread t) {
        // 拿的是 Thread 的变量 
        return t.threadLocals;
}

然后我们再看一下

    static class ThreadLocalMap {

        static class Entry extends WeakReference<ThreadLocal<?>> {
            /** The value associated with this ThreadLocal. */
            Object value;

            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                value = v;
            }
        }

WeakReference 继承自Reference , 这个类我们在上面的源码分析讲过 , 它里面有一个重要的成员变量 reference , 这个变量会和 gc 的时候有关 , 也就是引用 , 假如一个对象没了引用 , 毫无疑问肯定就会给回收了 .

我们以一个例子来学习 ThreadLocal 使用 WeakReference 的原理

public class ThreadLocalDemo {
    public static void main(String[] args) throws InterruptedException {
        firstStack();
        // System.gc();
        Thread.sleep(1000);
        Thread thread = Thread.currentThread();
        System.out.println(thread); // 在这里打断点,观察thread对象里的ThreadLocalMap数据

    }
    // 通过是否获取返回值观察A对象里的local对象是否被回收
    private static A firstStack(){
        A a = new A();
        System.out.println("value: "+ a.get());
        return a;
    }
    private static class A{
        private ThreadLocal<String> local = ThreadLocal.withInitial(() -> "in class A");

        public String get(){
            return local.get();
        }
        public void set(String str){
            local.set(str);
        }

    }
}

我们先对 System.gc(); 这一句注释掉 , 然后打下短点 , 得到下面的堆栈信息 , 看到 ThreadLocal 相关的信息 , 可以看到 , 此时 reference 还是有值的.

img

假如我们此时放开注释

img

虚引用 (PhantomReference)

public class Cleaner extends PhantomReference<Object> {
        ...
}

参考资料

posted @ 2023-07-10 10:30  float123  阅读(13)  评论(0编辑  收藏  举报