美文网首页
强引用、软引用、弱引用、虚引用以及ThreadLocal原理

强引用、软引用、弱引用、虚引用以及ThreadLocal原理

作者: 纳米君 | 来源:发表于2019-06-29 11:23 被阅读0次
    一. 强引用、软引用、弱引用和虚引用
    • 强引用:使用最普遍的引用,一般情况下,垃圾回收器绝对不会回收它。内存不足时,抛出OOM。
    String s = new String("hello");
    s = null; //不加该行,会输出hello
    System.gc(); //垃圾回收
    System.out.println(s);
    
    输出结果:null
    
    对象只有在创建它的方法执行结束才会被回收,或者主动设置obj = null。
    
    • 软引用:内存空间足够,垃圾回收器不会回收它。反之,则回收。适用于缓存,而且不会OOM。
    SoftReference<Object[]> reference = new SoftReference<>(new Object[300000000]);
    System.out.println(reference.get());
    Object[] objects = new Object[100000000];// 3
    System.out.println(reference.get());
    
    输出结果:
    [Ljava.lang.Object;@4554617c
    null
    
    结果说明执行代码3时,内存不够,垃圾回收器主动回收了软引用指向的对象。
    PS:Object数组长度根据JVM配置不同而不同。
    
    • 弱引用:只有当垃圾回收器扫描到弱引用指向的对象时,才会回收它。生命周期比软引用更短。ThreadLocal的key使用了弱引用。
    WeakReference<String> reference = new WeakReference<>(new String("hello"));
    System.out.println(reference.get());
    System.gc(); //垃圾回收
    System.out.println(reference.get());
    
    输出结果:
    hello
    null
    
    • 虚引用:在任何时候都可能被垃圾回收器回收,必须与引用队列关联使用。
    ReferenceQueue<String> queue = new ReferenceQueue<>();
    PhantomReference<String> reference = new PhantomReference<>(new String("hello"), queue);
    System.out.println(reference.get());
    
    输出结果:
    null
    
    二. ThreadLocal

    一个线程可以有多个ThreadLocal实例。其作用是存储线程本地变量,独享资源,避免和主内存通信,从而提高效率。

    原理:都是操作线程中的ThreadLocalMap对象。
    set(obj): 获取当前线程中的ThreadLocalMap,以ThreadLocal实例为keyobjvalue,并且key是弱引用。也就是说ThreadLocal实例(未被其他变量强引用)被垃圾回收器扫描到就会被回收,从而导致key = null。这就是为什么get、set、remove的时候都会有清除Entry[]key = null的数据的步骤。

    remove():会把当前key、value、key-value所在位置Entry[i]置为null,以及清除Entry[]中从i到末尾上key = null的数据。

    内存泄露:key是弱引用,所以垃圾回收器会主动回收。但是valueEntry[i]都是强引用,只有线程销毁的时候才会被回收。当线程长时间未被销毁,或者线程池循环利用线程的时候,valueEntry[i]一直被强引用,不会被垃圾回收器回收,可能会造成OOM。

    解决方法:使用完务必调用remove()方法,防止内存泄漏。


    以上。

    相关文章

      网友评论

          本文标题:强引用、软引用、弱引用、虚引用以及ThreadLocal原理

          本文链接:https://www.haomeiwen.com/subject/ylwucctx.html