Netty内存管理系统原理八

Java中的引用类型:

强引用

软引用:缓存

public SoftReference(T referent) {
    super(referent);
this.timestamp = clock;
}
//ReferenceQueue可传可不传
public SoftReference(T referent, ReferenceQueue<? super T> q) {
    super(referent, q);
    this.timestamp = clock;
}

弱引用:伴生(Scala)引用数据

public WeakReference(T referent) {
    super(referent);
}
//ReferenceQueue可传可不传
public WeakReference(T referent, ReferenceQueue<? super T> q) {
    super(referent, q);
}

虚引用:对象跟踪,不是用来存数据的,调用get()永远返回null,

//ReferenceQueue必传
public PhantomReference(T referent, ReferenceQueue<? super T> q) {
    super(referent, q);
}

Finalize引用(FinalReference):用户不可见,重写finalize方法自动生成,JVM用的

public abstract class Reference<T> {
    private static class ReferenceHandler extends Thread {
        ReferenceHandler(ThreadGroup g, String name) {
            super(g, name);
        }
        public void run() {
            while (true) {
                tryHandlePending(true);
            }
        }
        static boolean tryHandlePending(boolean waitForNotify) {
            Reference<Object> r;
            Cleaner c;
            try {
                synchronized (lock) {
                    if (pending != null) {
                        r = pending;
                        
                        //当 DirectByteBuffer被 gc时,jvm垃圾回收线程会将 Cleaner引用加入到
                        //pendding队列中去,比如DirectByteBuffer,这里会赋值给c
                        c = r instanceof Cleaner ? (Cleaner) r : null;
                        // unlink 'r' from 'pending' chain
                        pending = r.discovered;
                        r.discovered = null;
                    } else {
                        if (waitForNotify) {
                            lock.wait();
                        }
                        // retry if waited
                        return waitForNotify;
                    }
                }
            } catch (OutOfMemoryError x) {
                Thread.yield();
                // retry
                return true;
            } catch (InterruptedException x) {
                // retry
                return true;
            }
            //这里就会执行DirectByteBuffer中的clean方法
            // Fast path for cleaners
            if (c != null) {
                c.clean();
                return true;
            }
            //如果是Cleaner上一步就直接返回了,如果不是,那就会放到ReferenceQueue中。这个
            //ReferenceQueue就是我们实例化时传进来的
            ReferenceQueue<? super Object> q = r.queue;
            if (q != ReferenceQueue.NULL) q.enqueue(r);
            return true;
        }
    }

    //链表的头部,是static的
    private static Reference<Object> pending = null;
    //链表的next
    transient private Reference<T> discovered;  /* used by VM */
    static {
        ThreadGroup tg = Thread.currentThread().getThreadGroup();
        for (ThreadGroup tgn = tg;
             tgn != null;
             tg = tgn, tgn = tg.getParent());
        Thread handler = new ReferenceHandler(tg, "Reference Handler");
        handler.setPriority(Thread.MAX_PRIORITY);
        handler.setDaemon(true);
        handler.start();
        SharedSecrets.setJavaLangRefAccess(new JavaLangRefAccess() {
            @Override
            public boolean tryHandlePendingReference() {
                return tryHandlePending(false);
            }
        });
    }
}
boolean enqueue(Reference<? extends T> r) { /* Called only by Reference class */
    synchronized (lock) {
        ReferenceQueue<?> queue = r.queue;
        if ((queue == NULL) || (queue == ENQUEUED)) {
            return false;
        }
        assert queue == this;
        //使用头插法放入队列
        r.queue = ENQUEUED;
        r.next = (head == null) ? r : head;
        head = r;
        queueLength++;
        if (r instanceof FinalReference) {
            sun.misc.VM.addFinalRefCount(1);
        }
        lock.notifyAll();
        return true;
    }
}

pending是一个静态的,因为ReferenceHandler要处理所有引用,那么所有引用都必须得挂到这个链表上,那么如何让所有引用对象共享同一个链表呢?所以就设置成static的。

为什么discovered是实例类型不是静态类型呢?

因为我的对象是不同的,每种引用类型都有一个实例变量,所以每个引用类型都有一个Reference,discovered是指向下一个实例变量的,所以也是实例变量

sun.misc.VM.addFinalRefCount(1);这一步是看对象有没有重写过finalize(),如果重写过,那就引用计数+1,所以真正回不回收还要看执行完finalize(),有可能起死回生。

JVM是怎么把引用对象挂到pending列表的呢?

NIO使用一个虚引用解决堆外内存回收问题,那Netty怎么解决呢?

道理一样,也是给ByteBuf添加一个虚引用,当引用被干掉时去检查ByteBuf引用的那块内存是否回收

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值