美文网首页
强软弱虚(关键词: ThreadLocal,堆外内存)

强软弱虚(关键词: ThreadLocal,堆外内存)

作者: 每皮1024 | 来源:发表于2021-01-22 19:51 被阅读0次

前言

  • 引用的作用就是在GC的时候用作判断,一般采用的根可达算法(引用计数法会有循环引用的问题,所以我们不用)
  • 内存泄漏:我们不再使用一个对象,但其由于仍然有引用指向它,导致一直无法被垃圾回收器回收,这个称为内存泄漏

强引用

普通常见的引用

示例

public class NormalReference {
    public static void main(String[] args) throws IOException {
        M = new M();
        m = null;
        System.gc();//DisableExplicitGC
        System.in.read();
    }
}

软引用

示例

软引用在内存够用时不会被回收,在内存不够发生GC时会被回收

// 前提:JVM启动时-Xmx设置为20M
public class SoftReference {
    public static void main(String[] args) throws IOException {
        // m在栈中,堆中有一个SoftReference对象,此引用为强引用;
        // SoftReference对象又有一个软引用指向一个byte数组,此引用为软引用
        SoftReference<Byte[]> m = new SoftReference<>(new byte[1024*1024*10]); //10M
        // 如果需要得到软引用的内容,使用软引用的get()方法即可
        System.out.println(m.get())//有输出,数组对象值

        System.gc();
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(m.get());//有输出,数组对象值

        // 再分配一个数组,heap将装不下,此时会将软引用的对象给回收
        byte[] b = new byte[1024*1024*15];
        System.out.println(m.get());//null
    }
}

用途

缓存,例如常用大图片

弱引用

弱引用的对象,只要出现了GC就会被回收,适合ThreadLocal这种对象,因为不仅本身有强引用,在线程内部又会有key的弱引用,采用此引用可以保证强引用消失时能够被GC掉而不造成内存泄漏

示例

// 弱引用:被问到最多的一个
public class WeakReference {
    public static void main(String[] args) throws IOException {
        WeakReference<M> m = new WeakReference<>(new M());

        System.out.println(m.get());// 有输出
        System.gc();
        System.out.println(m.get());// null,一旦GC就直接回收了

        ThreadLocal<M> tl = new ThreadLocal<>();
        tl.set(new M());
        tl.remove();
    }
}

// ThreadLocal源码
public void set(T value) {
    Thread t = Thread.currentThread();
    // 根据当前线程对象获得一个map,然后往当前线程的map(threadLocals)里面放key value,注意key是ThreadLocal对象 
    ThreadLocalMap map = getMap(t);
    if (map != null) {
        map.set(this, value);
    } else {
        createMap(t, value);
    }
}
ThreadLocalMap getMap(Thread t) {
  // 可以看到这个map实际上是线程自己的一个map
    return t.threadLocals;
}
private void set(ThreadLocal<?> key, Object value) {
    // We don't use a fast path as with get() because it is at
    // least as common to use set() to create new entries as
    // it is to replace existing ones, in which case, a fast
    // path would fail more often than not.
    Entry[] tab = table;
    int len = tab.length;
    int i = key.threadLocalHashCode & (len-1);
    for (Entry e = tab[i];
         e != null;
         e = tab[i = nextIndex(i, len)]) {
        ThreadLocal<?> k = e.get();
        if (k == key) {
            e.value = value;
            return;
        }
        if (k == null) {
            replaceStaleEntry(key, value, i);
            return;
        }
    }
    // 可以看到key value最终是一个Entry的形式放进threadLocals里的
    tab[i] = new Entry(key, value);
    int sz = ++size;
    if (!cleanSomeSlots(i, sz) && sz >= threshold)
        rehash();
}
// Entry本身继承自弱引用
static class Entry extends WeakReference<ThreadLocal<?>> {
    /** The value associated with this ThreadLocal. */
    Object value;

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

用途

  • ThreadLocal:当使用ThreadLocal对象进行set(value)时,它会先去拿到当前线程的ThreadLocalMap threadLocals,然后往该map里面放key(ThreadLocal
    对象)和value,这样每次get出来的内容,一定是从当前线程独享的map里获取的信息。
    • 当往当前线程自身map里面放入以ThreadLocal对象为key的entry时,产生了两个引用:外部建立ThreadLocal对象时的强引用,当前线程内部threadLocals这个map的key的弱引用
      • 当外部强引用消失时,内部key的弱引用,就能保证这个ThreadLocal对象能够在GC时被回收掉内存泄漏点一(弱引用帮我们解决了这个问题):ThreadLocal对象
      • 当外部ThreadLocal对象的强引用消失时,线程内部的threadLocals map里该ThreadLocal对象key对应的这一行也就再也无法获得(正常是通过tl.get()方法获得),此时需要我们自己手动去执行tl.remove()将这一行的value给删除内存泄漏点二:当前线程threadLocals map中ThreadLocal对象作为key对应的那个value

虚引用

示例

// 虚引用:永远get不到
// 虚引用:永远get不到
public class PhantomReference {
    private static final List<Object> LIST = new LinkedList<>();
    // 首先要有一个队列
    private static final ReferenceQueue<> QUEUE = new ReferenceQueue<>();

    public static void main(String[] args) throws IOException {
        // 虚引用pr,指向PhantomReference对象
        // PhantomReference对象,指向M对象,并且指明该虚引用所属队列是哪一个(QUEUE)
        PhantomReference<M> pr = new PhantomReference<>(new M(), QUEUE);

        // 此线程不断往加内存,使其膨胀,让垃圾回收器开始工作。(每次垃圾回收器回收一次,虚引用对象就会被回收)
        new Thread(() -> {
            while(true) {
                LIST.add(new byte(1024*1024));
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    Thread.currentThread().interrupt();
                }
                System.out.println(pr.get());// null
            }
        }).start();

        // 监控线程,监控QUEUE是否有内容,拿出来即表明堆外内存已经回收
        new Thread(() -> {
            while(true) {
                Reference<? extends M> poll = QUEUE.poll();
                if(poll != null) {
                    System.out.println("--- 虚引用对象被jvm回收了 ---" + poll);
                }
            }
        }).start();
    }
}

用途

  • 管理堆外内存,Netty中的零拷贝
  • 一、从网络上访问一个数据的步骤:
    • 网卡读到数据,交给操作系统
    • 操作系统将数据积攒成一个buffer
    • 如果JVM需要,将会复制到JVM管理的内存区
  • 二、如果JVM想要把一块数据从网络上写出去
    * JVM需要交给操作系统,再写给网卡
  • 以上两种情况,其中JVM与系统之间的复制,可以省略->堆外内存管理(直接内存管理)。
    • 在NIO中可以通过Java对象DirectBuffer指向堆外内存
    • 在垃圾回收器中有一个垃圾线程,专门监听DirectByteBuffer对象,如果没了就要去把堆外的内存去回收。如何做到?给这个对象加一个虚引用,则能够在该对象被回收时,其信息会被添加到队列QUEUE里面,上面的监听线程就是监听QUEUE的

待自学点

AtomicReference

相关文章

  • 强软弱虚(关键词: ThreadLocal,堆外内存)

    前言 引用的作用就是在GC的时候用作判断,一般采用的根可达算法(引用计数法会有循环引用的问题,所以我们不用) 内存...

  • Java中的强软弱虚引用,还有你知道为什么ThreadLocal

    Java中的类型引用 强软弱虚 强引用 栈内存指向了堆内存 当栈内存的m指向堆内存的new M(),当m=null...

  • 高并发编程之ThreadLocal

    强软弱虚 ThreadLocal 为什么Entry 的key 使用的是弱引用?

  • 强软弱虚引用以及threadlocal

    https://blog.csdn.net/qq1805696978/article/details/104106517

  • 堆外内存和虚引用

    堆外内存 概念 堆内内存在 Java 中对象都是在堆内分配的,通常我们说的JVM 内存也就指的堆内内存,堆内内存完...

  • Android面试题大全-Java基础篇

    Java基础 内存泄漏的场景 强软弱虚引用分别什么区别 什么场景下使用虚引用 ClassLoader的双亲委派原理...

  • Java中的四种引用

    1.强软弱虚四种引用 1.1 强引用 执行结果: 解释:强引用是JVM的默认实现,即使内存不足会导致OOM(Out...

  • 强软弱虚引用

    四种引用的区别: 强引用:如果一个对象具有强引用,那垃圾回收器绝不会回收它。软引用:如果一个对象只具有软引用,则内...

  • 强软弱虚引用

    一、强引用(StrongReference) 不会回收有强引用的对象。 除了强引用,其他的引用都需要借助java....

  • 强软弱虚引用

    强引用 简介: 强引用 (Strong Reference) 特征: 只有手动赋值为 null 才会被垃圾回收线程...

网友评论

      本文标题:强软弱虚(关键词: ThreadLocal,堆外内存)

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