netty源码之内存池

Posted better_hui

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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的次数,对性能提升是非常可观的

2、非池化Buffer

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

三、内存分配

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

1、PooledDirectByteBuf对象池的使用

跟进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中两者的关系:

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

3、堆外内存的分配

进入PooledByteBufAllocator的构造函数

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

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

四、apache的对象池

commons-pool

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

以上是关于netty源码之内存池的主要内容,如果未能解决你的问题,请参考以下文章

netty源码之内存池

netty源码之内存池

高性能Netty之内存池源码分析

Netty内存池之PoolChunk

Netty源码分析(七) PoolChunk

Netty源码分析:PoolArena