netty源码之内存池(代码片段)

better_hui better_hui     2023-03-09     332

关键词:

目录

一、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源码之内存池(代码片段)

目录一、DirectBuffer和HeapBuffer对外直接内存缓冲堆内存缓冲IO二、Netty的池化池化的好处netty的缓冲池使用1、池化Buffer2、非池化Buffer三、内存分配1、PooledDirectByteBuf对象池的使用2、回收池Recycler原理3、堆外内存的分配四、apache的对... 查看详情

netty源码之内存池(代码片段)

目录一、DirectBuffer和HeapBuffer对外直接内存缓冲堆内存缓冲IO二、Netty的池化池化的好处netty的缓冲池使用1、池化Buffer2、非池化Buffer三、内存分配1、PooledDirectByteBuf对象池的使用2、回收池Recycler原理3、堆外内存的分配四、apache的对... 查看详情

stl源码分析之内存池(代码片段)

前言上一节只分析了第二级配置器是由多个链表来存放相同内存大小,当没有空间的时候就向内存池索取就行了,却没有具体分析内存池是怎么保存空间的,是不是内存池真的有用不完的内存,本节我们就具体来分析一下内存池staticda... 查看详情

netty源码分析之服务端启动(代码片段)

Netty服务端启动代码:publicfinalclassEchoServerstaticfinalintPORT=Integer.parseInt(System.getProperty("port","8007"));publicstaticvoidmain(String[]args)throwsException//Configuretheserver.EventLoopGroupboss 查看详情

netty源码之接收连接(代码片段)

目录 接收链接netty的接收连接前话1、bossGroup轮询链接事件2、bossGroup创建socketChannel3、ServerBootstrapAcceptor注册到worker线程4、workerGroup将socketChannel注册到选择的NioEventLoop的selector5、workerGroup注册读事件接收链接NIO的读事件while(!stop)//... 查看详情

netty源码之关闭服务(代码片段)

目录一、前言二、客户端的关闭服务1、进入workerGroup.shutdownGracefully()2、NioEventLoop.run()关闭的入口3、closeAll()4、confirmShutdown()方法5、cleanup()关闭selector一、前言这里的关闭包含了boss/worker两个线程,是netty提供的优雅退出。二、... 查看详情

netty源码之关闭服务(代码片段)

目录一、前言二、客户端的关闭服务1、进入workerGroup.shutdownGracefully()2、NioEventLoop.run()关闭的入口3、closeAll()4、confirmShutdown()方法5、cleanup()关闭selector一、前言这里的关闭包含了boss/worker两个线程,是netty提供的优雅退出。二、... 查看详情

netty内存池(5w长文+史上最全)(代码片段)

文章很长,建议收藏起来慢慢读!疯狂创客圈总目录语雀版|总目录码云版|总目录博客园版为您奉上珍贵的学习资源:免费赠送经典图书:《Java高并发核心编程(卷1)》面试必备+大厂必备+涨薪必备加尼... 查看详情

netty源码之启动流程(代码片段)

一、前言 ourthread就是我们的主线程,bossthread就是netty的bossGroup线程,也就是reactor的主线程二、启动启动的本质启动的实质是什么?实际上我们只需要找到javanio的那些代码就可以了1、打开一个selector2、打开一个channel... 查看详情

netty源码之启动流程(代码片段)

一、前言 ourthread就是我们的主线程,bossthread就是netty的bossGroup线程,也就是reactor的主线程二、启动启动的本质启动的实质是什么?实际上我们只需要找到javanio的那些代码就可以了1、打开一个selector2、打开一个channel... 查看详情

netty源码分析之处理新连接(代码片段)

Netty服务端处理新连接的流程:1.检测新连接2.基于NioServerSocketChannel创建客户端的NioSocketChannel3.分配客户端channel的线程,注册线程所对应的selector4.向selector注册读事件 新连接检测  服务端在创建完服务端的NioServerSocketChannel... 查看详情

netty源码之断开连接(代码片段)

目录一、前言二、正常关闭1、关闭前的处理工作2、doClose0调用jdk的close关闭channel3、fireChannelInactiveAndDeregister传播关闭、解绑定事件4、doDeregister取消selector上的selectorKey三、异常关闭四、总结一、前言关闭的逻辑是在read方法里ÿ... 查看详情

netty源码之断开连接(代码片段)

目录一、前言二、正常关闭1、关闭前的处理工作2、doClose0调用jdk的close关闭channel3、fireChannelInactiveAndDeregister传播关闭、解绑定事件4、doDeregister取消selector上的selectorKey三、异常关闭四、总结一、前言关闭的逻辑是在read方法里ÿ... 查看详情

netty源码之写数据(代码片段)

目录前言和快递比较一下几种场景发送数据的分类写数据flush数据前言write是把数据写到buf里flush是将数据发出去writeAndFlush写入数据到buf并立刻发送出去和快递比较一下 几种场景1、netty协数据,写不进去了,会停止写ÿ... 查看详情

netty源码之写数据(代码片段)

目录前言和快递比较一下几种场景发送数据的分类写数据flush数据前言write是把数据写到buf里flush是将数据发出去writeAndFlush写入数据到buf并立刻发送出去和快递比较一下 几种场景1、netty协数据,写不进去了,会停止写ÿ... 查看详情

netty源码之读取数据(代码片段)

目录前话1、读数据的技巧2、简约流程3、读数据的本质流程1、读取数据前话1、读数据的技巧  2、简约流程 3、读数据的本质 流程读数据的轮询和接收连接是一样的,都是在NioEventLoop对象的run方法里,但是在最终读的... 查看详情

netty源码之读取数据(代码片段)

目录前话1、读数据的技巧2、简约流程3、读数据的本质流程1、读取数据前话1、读数据的技巧  2、简约流程 3、读数据的本质 流程读数据的轮询和接收连接是一样的,都是在NioEventLoop对象的run方法里,但是在最终读的... 查看详情

netty源码分析:poolchunklist(代码片段)

Netty源码分析:PoolChunkList在博文Netty源码分析:PoolArena中我们知道,在第一次申请内存时,会调用如下的allocateNormal方法来新建一个Chunk,然后在此Chunk上分配内存。分配完成之后会将这个Chunk添加到名为qInit的Po... 查看详情