zoukankan      html  css  js  c++  java
  • 强软弱虚四种引用和ThreadLocal内存泄露

    强软弱虚四种引用

    1)强引用:平时new出来的对象,只要有引用在 即使发生GC也回收不了

    2)软引用:空间不够就回收,软引用适合做缓存,空间足够就放在那里,不够用就回收

    ***
     * 空间不够就会回收
     * 软引用适合做缓存(空间足够就放在那里 不够用会回收)
     * -Xmx=20M
     */
    public class T02_SoftReference {
    
        public static void main(String[] args) throws Exception{
            /***
             * m指向SoftReference 对象
             * SoftReference 对象里面还有一个引用 是软引用 指向一个字节数组(10M)
             */
            SoftReference<byte[]> m = new SoftReference<>(new byte[1024*1024*10]);
            System.out.println(m.get());
            System.gc(); /**gc不是在主线程 所以sleep 1s**/
            Thread.sleep(1000);
            System.out.println(m.get());
            //在new一个数组(强引用) heap将装不下,这时候系统会垃圾回收一次 如果不够 就把软引用
            byte[] b=new byte[1024*1024*15];
            System.out.println(m.get());
        }

    软引用的内存结构(虚引用和弱引用的内存结构图也相似)

    3)弱引用:遇到GC就会回收,解决ThreadLocal内存泄露的问题(参考下面ThreadLocal泄露)

      当这个弱引用指向对象M的时候,还有一个强引用执向M的时候,只要强引用消失掉,这个M对象就应该被回收(不需要在额外管理那个弱引用了),这就是弱引用的用处

        一般用在容器里,如:weekHashMap

    4)虚引用:管理堆外内存,比如DirectByteBuffer(NIO的API 直接指向堆外内存 不需要Copy到JVM中 操作系统直接管理,JVM回收不了 0拷贝)

    即:jvm内部可以访问操作系统管理的内存(用户空间可以管理内核空间的内存)

    当某个引用被回收的时候 会通知队列(把信息填到对面里面当中),然后由GC线程清理堆外内存

    public class T04_PhantomReference {
        public static final List<Object> LIST = new ArrayList<>();
        public static final ReferenceQueue<M> QUEUE = new ReferenceQueue<>();
        public static void main(String[] args) {
            PhantomReference<M> phantomReference=new PhantomReference<>(new M(),QUEUE);
            new Thread(() -> {
               while (true){
                   LIST.add(new byte[1204*1024*10]);
                   try {
                       Thread.sleep(1000);
                   } catch (InterruptedException e) {
                       e.printStackTrace();
                       Thread.currentThread().interrupt();
                   }
                   /**虚引用永远拿不到值*/
                   System.out.println(phantomReference.get());
               }
            }).start();
    
            new Thread(() -> {
               while (true){
                   Reference<? extends M> poll=QUEUE.poll();
                   if (poll!=null){
                       System.out.println("虚引用被JVM回收了-----"+poll);
                   }
               }
            }).start();
    
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
    }

    ThreadLocal内存泄露

    1) ThreadLocal内部使用虚引用防止内存泄露:我们看ThreadLocal的set方法

    ThreadLocal的set方法 后面的实现就是往Entry数组中 通过Entry的构造方法增加一个对象,

    其中Entry构造里面调用了super(k),相当于用一个弱引用指向key。也就是指向ThreadLocal的引用是弱引用

    Entry里面这个key是被一个弱引用指向的ThreadLocal对象

     ThreadLocal<M> t = new ThreadLocal<>();
            t.set(new M());

    ThreadLocal的set方法 后面的实现就是往Entry数组中 通过Entry的构造方法增加一个对象,

    如果我们用强引用的话:方法结束 ThreadLocal应该要回收掉

    但是往线程t里面set的一个对象M,即使t为null了,Entry里面 依然会有一个强引用指向ThreadLocal(ThreadLocal对象既被t引用指向, 还被一个弱引用指向)

    这个时候 因为Entry中的强引用会可能产生内存泄露(这个需要结合ThreadLocal的源码理解)

    除非线程结束,但是有些线程是7X24小时不断开着的(比如NIO的Selector轮训)

    2)ThreadLocal用完remove()防止内存泄露

    因为源代码提示使用static关键字修饰ThreadLocal,

    这时候:如果不进行remove()操作(remove就是把整个Entry从ThreadLocalMap里面删除) 上面t所持有的ThreadLocal对象也不会被释放的

    一直set() 而不remove()也会引起内存泄露

    所以:如果ThreadLocal被static修饰时,如果忘记remove() 也可能引起内存泄露

  • 相关阅读:
    Lucene学习总结之二:Lucene的总体架构
    Lucene学习总结之三:Lucene的索引文件格式(1)
    android开发_SeekBar进度条
    android开发_mp3_player音乐播放器
    Lucene学习总结之一:全文检索的基本原理
    android开发_Intent_requestCode_resultCode页面之间的跳转
    android开发_Location位置定位
    .NET Remoting Basic(7)信道
    .NET Remoting Basic(1)概览
    .NET Remoting Basic(5)多服务器访问和程序集共享
  • 原文地址:https://www.cnblogs.com/ssskkk/p/12739557.html
Copyright © 2011-2022 走看看