netty的对象的生命周期管理——引用计数

一、何谓引用计数

1.1 引用计数

引用计数是一种简单高效的垃圾回收机制,当一个新的引用指向对象的时候,增加引用计数;去掉一个引用,就减小一个引用计数;当引用计数减到0的时候,就释放掉这个引用计数。


1.2 引用计数的增减

   对于一个引用计数的对象,最核心的操作就是引用计数的增减。但是,在一个并发场景下,必须保证引用计数增减的原子性。最简单的实现方法如下:

private static class AtomicIntSync implements Atomic {
        private int i = 0;

        public AtomicIntSync(int i) {
            this.i = i;
        }

        @Override
        public synchronized int incrementAndGet() {

            return ++i;
        }
    }

这种方法通过synchonized关键字,为自增操作加锁,而且java对这个关键字做了很多的优化,相对而言性能还是挺高的。


稍微复杂一点的方式是使用CAS(Compare and swap)的方式,CAS的语义是“我认为V的值应该为A,如果是,那么将V的值更新为B,否则不修改并告诉V的值实际为多少”,实现如下:

private static class AtomicIntCas implements Atomic {
        private volatile int        i = 0;
        private static final Unsafe unsafe;
        private static long         off;
        static {
            Unsafe tmp = null;
            try {
                //获取unsafe
                Field field = Unsafe.class.getDeclaredField("theUnsafe");
                field.setAccessible(true);
                tmp = (Unsafe) field.get(null);
                //获取i字段在类中的偏移
                off = tmp.fieldOffset(AtomicIntCas.class.getDeclaredField("i"));
            } catch (Throwable e) {
                e.printStackTrace();
            }
            unsafe = tmp;
        }

        public AtomicIntCas(int i) {
            this.i = i;
        }

        @Override
        public int incrementAndGet() {
            for (;;) {
                int m = i;
                int add = m + 1;
                if (unsafe.compareAndSwapInt(this, off, m, add)) {
                    return add;
                }
            }
        }
    }
整个性能对比的程序如附件所示,运行后的性能对比曲线如下,(x轴为线程的数量,y轴为每一个线程运行的时间):


由上图可知,CAS方式整体性能是好于使用synchronized的这种锁的方式的。


二、引用计数的应用

     引用计数的应用非常多,大名鼎鼎的Python语言其简单对象的垃圾回收机制就用的引用计数,netty的大量数据结构也使用的是引用计数。因为引用计数的垃圾回收实现简单,而且非常高效,特别是在分布式环境中,其性能真心杠杠的。


三、引用计数的局限

    引用计数很难解决的场景是:A引用B,B同时引用A,当A和B都不使用了,A和B的引用都会是1,导致这种场景下的引用计数无法变成0,导致A和B都不能被释放。

四、netty的引用计数的实现

    netty的引用计数的接口为io.netty.util.ReferenceCounted,netty很多重要的数据结构都是继承这个接口,比如ByteBuf,其核心实现参考:io.netty.util.AbstractReferenceCounted,其实现方式和上面的CAS的实现方法原理基本一致。

过程是:

1、通过Unsafe的方法,计算引用计数字段在AbstractReferenceCounted类中的偏移

2、通过Unsafe提供的CAS方法,将新的数据搬迁到引用计数字段所在的位置(AbstractReferenceCounted对象的地址+偏移)

3、如果CAS操作成功,就返回;否则计算新的引用计数,然后调用步骤2


五、netty的内存泄露检查

详见下一篇文章~

六、netty的引用计数的使用举例

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值