netty AbstractReferenceCountedByteBuf类

AbstractReferenceCountedByteBuf

作用

AbstractReferenceCountedByteBuf类提供了引用计数的功能,其所有的子类都可以使用该功能防止内存泄漏。

属性

REFCNT_FIELD_OFFSET:refCnt字段在内存中的地址偏移量

AIF_UPDATER:refCnt字段更新器

updater:更新器

refCnt:保存引用计数的字段

private static final long REFCNT_FIELD_OFFSET =
        ReferenceCountUpdater.getUnsafeOffset(AbstractReferenceCountedByteBuf.class, "refCnt");

private static final AtomicIntegerFieldUpdater<AbstractReferenceCountedByteBuf> AIF_UPDATER =
        AtomicIntegerFieldUpdater.newUpdater(AbstractReferenceCountedByteBuf.class, "refCnt");

private static final ReferenceCountUpdater<AbstractReferenceCountedByteBuf> updater =
        new ReferenceCountUpdater<AbstractReferenceCountedByteBuf>() {
    @Override
    protected AtomicIntegerFieldUpdater<AbstractReferenceCountedByteBuf> updater() {
        return AIF_UPDATER;
    }
    @Override
    protected long unsafeOffset() {
        return REFCNT_FIELD_OFFSET;
    }
};

@SuppressWarnings("unused")
private volatile int refCnt = updater.initialValue();

由initialValue()方法的实现可知refCnt的初始值为2

public final int initialValue() {
	return 2;
}

关于AtomicIntegerFieldUpdater类和ReferenceCountUpdater类

ReferenceCountUpdater类的部分方法如下所示,updater()和unsafeOffset()方法是抽象方法,需要具体的子类提供实现。而AtomicIntegerFieldUpdater是JDK提供的一个可以通过原子更新的方式修改指定字段的工具。

故ReferenceCountUpdater类的功能是可以通过CAS的方式直接修改某个类的一个字段的值。updater()方法用于提供修改字段值的工具类,unsafeOffset()方法用于提供要修改的字段在内存中的地址偏移量。

在这里插入图片描述

为什么ReferenceCountUpdater中持有的refCnt的值是偶数?

refCnt是偶数则表示当前缓冲区的状态为正常状态,如果refCnt是奇数则表示缓冲区的状态为待销毁状态。缓冲区引用计数的真实值为refCnt/2。

构造函数:

调用父类(AbstractByteBuf)的构造方法设置ByteBuf的最大容量:

protected AbstractReferenceCountedByteBuf(int maxCapacity) {
    super(maxCapacity);
}

获取引用计数:

@Override
public int refCnt() {
    return updater.refCnt(this);
}

updater的refCnt方法如下:

public final int refCnt(T instance) {
    return realRefCnt(updater().get(instance));
}

updater().get(instance)的作用是获取instance对象指定字段的值(为真实值的2倍),再调用realRefCnt(int rawCnt)方法计算引用的真实值。

realRefCnt(int rawCnt)方法如下,

/**
* 判断rawCnt的值是否为偶数,如果rawCnt是偶数则返回rawCnt无符号右移1位的结果
* 如果rawCnt为奇数,则返回0
*/
private static int realRefCnt(int rawCnt) {
    return rawCnt != 2 && rawCnt != 4 && (rawCnt & 1) != 0 ? 0 : rawCnt >>> 1;
}

增加引用计数的值:

@Override
public ByteBuf retain() {
    return updater.retain(this);
}

retain()方法委派updater类对refCnt进行增加,updater#retain(T instance)如下所示:

public final T retain(T instance) {
    return retain0(instance, 1, 2);
}

updater#retain0(T instance, final int increment, final int rawIncrement)方法如下所示:

/**
* 先执行操作,再进行校验
*/
private T retain0(T instance, final int increment, final int rawIncrement) {
    int oldRef = updater().getAndAdd(instance, rawIncrement);//CAS,先获取原值,再增加
    //如果oldRef为奇数,表示缓冲区已经被释放,则抛出异常
    if (oldRef != 2 && oldRef != 4 && (oldRef & 1) != 0) {
        throw new IllegalReferenceCountException(0, increment);
    }
    /**
    *	如果对oldRef增加后发生了溢出,即超出了Integer.MAX_VALUE的值,则对其进行回滚,并抛出异常
    */
    if ((oldRef <= 0 && oldRef + rawIncrement >= 0)
            || (oldRef >= 0 && oldRef + rawIncrement < oldRef)) {
        // overflow case
        updater().getAndAdd(instance, -rawIncrement);
        throw new IllegalReferenceCountException(realRefCnt(oldRef), increment);
    }
    return instance;
}

减少引用计数的值

@Override
public boolean release() {
    return handleRelease(updater.release(this));
}

ReferenceCountUpdater#release(T instance)如下所示:

public final boolean release(T instance) {
    int rawCnt = nonVolatileRawCnt(instance);//通过Unsafe的方式获取引用计数的值
    return rawCnt == 2 ? tryFinalRelease0(instance, 2) || retryRelease0(instance, 1)
            : nonFinalRelease0(instance, 1, rawCnt, toLiveRealRefCnt(rawCnt, 1));
}

ReferenceCountUpdater#tryFinalRelease0(T instance, int expectRawCnt)方法:

通过cas的方式将引用计数的值修改为1

private boolean tryFinalRelease0(T instance, int expectRawCnt) {
    return updater().compareAndSet(instance, expectRawCnt, 1); // any odd number will work
}

ReferenceCountUpdater#retryRelease0(T instance, int decrement):\

代码逻辑如下:

1、获取instance实例中保存的rawCnt值,并计算出真实的refCnt值,即realCnt

2、如果要减少的引用值和真实的refCnt值相同,也即需要释放缓冲区对象,则调用tryFinalRelease0方法将refCnt

的数值修改为1(只要修改为奇数即可)

3、如果要减少的引用值小于真实的refCnt值,则通过cas修改refCnt的值

4、调用Thread.yield()方法释放出CPU的执行权,因为修改引用计数的逻辑在整个系统逻辑的优先级并不高,所以让出执行权有利于提高高并发下的系统吞吐量

/**
* 自旋的方式通过cas修改引用计数的值
*	
* rawCnt:instance对象中保存的值  realCnt:经过计算后得到的值(如果是偶数则除以2)
*/
private boolean retryRelease0(T instance, int decrement) {
    for (;;) {
        int rawCnt = updater().get(instance), realCnt = toLiveRealRefCnt(rawCnt, decrement);
        if (decrement == realCnt) {
            if (tryFinalRelease0(instance, rawCnt)) {
                return true;
            }
        } else if (decrement < realCnt) {
            // all changes to the raw count are 2x the "real" change
            if (updater().compareAndSet(instance, rawCnt, rawCnt - (decrement << 1))) {
                return false;
            }
        } else {
            throw new IllegalReferenceCountException(realCnt, -decrement);
        }
        Thread.yield();
    }
}

AbstractReferenceCountedByteBuf#handleRelease(boolean result)方法

private boolean handleRelease(boolean result) {
    if (result) {
        deallocate();
    }
    return result;
}

handleRelease方法调用deallocate()方法,该方法为一个抽象方法,具体的实现交由具体的子类完成

Spring Boot是一个用于创建独立的Spring应用程序的框架,它可以帮助我们快速地构建基于Spring的应用程序。而Netty是一个基于NIO的客户端服务器框架,可以快速开发可维护的高性能协议服务器和客户端。 在Spring Boot中实现Netty的handler,可以通过以下步骤来完成。首先,我们需要在Spring Boot应用程序的配置中添加Netty的相关依赖,例如io.netty:netty-all。然后,我们需要创建一个Netty的handler,这个需要继承自ChannelInboundHandlerAdapter,并实现其相关方法,用来处理客户端和服务器之间的消息传递。 在这个handler中,我们可以定义一些自定义的逻辑,例如处理客户端发送过来的消息并给予相应的响应。我们可以在这个中实现一些业务逻辑,如消息的解析和处理,然后再返回给客户端相应的结果。 同时,我们需要在Spring Boot应用程序的配置中初始化Netty的服务端,并将handler绑定到对应的端口上。如下所示: ```java @Configuration public class NettyConfig { @Value("${netty.server.port}") private int port; @Autowired private NettyServerHandler nettyServerHandler; @Bean public ServerBootstrap serverBootstrap() { ServerBootstrap serverBootstrap = new ServerBootstrap(); serverBootstrap.group(bossGroup(), workerGroup()) .channel(NioServerSocketChannel.class) .option(ChannelOption.SO_BACKLOG, 128) .childOption(ChannelOption.SO_KEEPALIVE, true) .childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) { ChannelPipeline pipeline = ch.pipeline(); // 添加自定义的handler pipeline.addLast(nettyServerHandler); } }); return serverBootstrap; } @Bean public NioEventLoopGroup bossGroup() { return new NioEventLoopGroup(); } @Bean public NioEventLoopGroup workerGroup() { return new NioEventLoopGroup(); } @PreDestroy public void destroy() { bossGroup().shutdownGracefully(); workerGroup().shutdownGracefully(); } } ``` 在上面的配置中,我们通过@Bean注解来初始化Netty的服务端,并将handler绑定到对应的端口上。最后,在使用Netty的handler时,我们需要注意线程安全性以及异常的处理。 综上所述,通过在Spring Boot应用程序中实现Netty的handler,可以实现客户端和服务端之间的消息传递和业务逻辑的处理。同时也可以充分利用Netty的高性能和可维护性来实现应用程序的高效运行。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值