netty源码之内存池

目录

一、DirectBuffer 和 HeapBuffer

对外直接内存缓冲

堆内存缓冲

IO

二、Netty的池化

池化的好处

netty的缓冲池

使用

1、池化Buffer

2、非池化Buffer

三、内存分配

1、PooledDirectByteBuf对象池的使用

2、回收池Recycler原理

3、堆外内存的分配

四、apache的对象池

commons-pool


一、DirectBuffer 和 HeapBuffer

对外直接内存缓冲

directBuffer是分配在直接内存(Direct Memory)上的内存区域,直接内存不是JVM 运行时数据区的一部分,也不是JVM规范定义的内存区域。

在jdk1.4开始NIO引入了Channel 和 Buffer的API包,我们可以通过调用native接口来申请直接内存,并关联一个JVM上的引用,当JVM内存上引用收回后 这块直接内存才能被操作系统回收。

堆内存缓冲

heapBuffer是分配在JVM堆内存区域的缓冲区,我们可以人为是一个byte[] 数组的封装形式、

IO

1、基于堆内存的IO操作 , 首先在堆内存申请一块内存数据 , 然后将数据copy至直接内存 , 然后再将直接内存上的数据发送到IO设备的缓冲区。

2、基于直接内存的IO操作 , 避免了堆内存到直接内存的数据copy ,加快访问速度,大大的提高性能。

3、DirectBuffer的缺点在于直接内存的分配与释放的代价相对比较大,因此,其适用于可复用的缓冲区

二、Netty的池化

池化的好处

1、资源的复用 , 减少内存申请和释放的性能损耗

2、减轻GC压力 , 避免内存抖动

3、内存资源可控

netty的缓冲池

在netty中,缓冲区有两种HeapBuffer 和 DirectBuffer ;

对应堆内存和直接内存的池化技术分别是PooledHeapByteBuf 和 PooledDirectByteBuf

使用

1、池化Buffer

netty通过PooledByteBufAllocator 可以创建基于内存池分配的ByteBuf对象(PooledHeapByteBuf、PooledDirectByteBuf),这样就避免了每次消息读写都申请和释放ByteBuf,这样很大程度减少了gc的次数,对性能提升是非常可观的

img

2、非池化Buffer

netty通过UnpooledByteBufAllocator可以创建非池化的ByteBuf对象

img

三、内存分配

启动的时候 , 我们可以设置内存分配是采用池化或者非池化的方式 。默认采用池化技术。

img

1、PooledDirectByteBuf对象池的使用

img

跟进RECYCLER.get()源码

@SuppressWarnings("unchecked")
    public final T get() {
        // 判断线程池的容量等于0则直接返回一个Object
        if (maxCapacityPerThread == 0) {
            return newObject((Handle<T>) NOOP_HANDLE);
        }
​
        // fastThreadLocal中获取一个stack
        Stack<T> stack = threadLocal.get();
        DefaultHandle<T> handle = stack.pop();
​
        // 试图从"池"中取一个handle,如果没有成功就new一个handle
        if (handle == null) {
            handle = stack.newHandle();
            handle.value = newObject(handle);
        }
        return (T) handle.value;
    }
​

在类中方法内回收对象的实现

private static final class DefaultHandle<T> implements Handle<T> {
        // 默认的回收对象的实现方式
        @Override
        public void recycle(Object object) {
            stack.push(this);// 将对象再放入栈中
        }
    }
​

2、回收池Recycler原理

对象池通过Recycler里面WeakOrderQueue、Stack 2个类来实现。 首先放一张图来展示一个stack中两者的关系:

img

1、为避免并发安全,每个线程都有自己的线程池,stack作为本线程对象池的核心,通过FastThreadLocal实现每个线程的本地化

3、堆外内存的分配

进入PooledByteBufAllocator的构造函数

img

img

继续跟进源码,传入的preferDirect最后作用于directByDefault,然后当directByDefault为true的时候,115行的代码会分配一个堆外内存

img

最终是调用了jdk的对外内存分配方法

img

四、apache的对象池

commons-pool

Apache Commons Pool开源软件库提供了一个对象池API和一系列对象池的实现,支持各种配置,比如活跃对象数或者闲置对象个数等。DBCP数据库连接池基于Apache Commons Pool实现。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值