内存使用技巧的目标
目标:
• 内存占用少(空间)
• 应用速度快(时间)
对 Java 而言:减少 Full GC 的 STW(Stop the world)时间
Netty 内存使用技巧 - 减少对像本身大小
例 1:用基本类型就不要用包装类:
例 2: 应该定义成类变量的不要定义为实例变量:
• 一个类 -> 一个类变量
• 一个实例 -> 一个实例变量
• 一个类 -> 多个实例
• 实例越多,浪费越多。
例 3: Netty 中结合前两者:
ty.channel.ChannelOutboundBuffer#incrementPendingOutboundBytes(long, boolean)
统计待写的请求的字节数
AtomicLong -> volatile long + static AtomicLongFieldUpdater
Netty 内存使用技巧 - 对分配内存进行预估
例 1:对于已经可以预知固定 size 的 HashMap避免扩容
可以提前计算好初始size或者直接使用
mon.collect.Maps#newHashMapWithExpectedSize
例 2:Netty 根据接受到的数据动态调整(guess)下个要分配的 Buffer 的大小。可参考
ty.channel.AdaptiveRecvByteBufAllocator
Netty 内存使用技巧 - Zero-Copy
例 1:使用逻辑组合,代替实际复制。
例如 CompositeByteBuf:
ty.handler.codec.ByteToMessageDecoder#COMPOSITE_CUMULATOR
例 2:使用包装,代替实际复制。
byte[] bytes = data.getBytes();
ByteBuf byteBuf = Unpooled.wrappedBuffer(bytes);
例 3:调用 JDK 的 Zero-Copy 接口。
Netty 中也通过在 DefaultFileRegion 中包装了 NIO 的 FileChannel.transferTo() 方法实
现了零拷贝:ty.channel.DefaultFileRegion#transferTo
Netty 内存使用技巧 - 堆外内存
•JVM 内部 -> 堆(heap) + 非堆(non heap)
• JVM 外部 -> 堆外(off heap)
使用堆外内存 :
• 优点:
• 更广阔的“空间 ”-> 破除堆空间限制,减轻 GC 压力
• 减少“冗余”细节(假设烧烤过程为了气氛在室外进行:烤好直接上桌:vs 烤好还
要进店内)-> 避免复制
• 缺点:
• 创建速度稍慢
• 堆外内存受操作系统管理
Netty 内存使用技巧 - 内存池
为什么引入对象池:
• 创建对象开销大
• 对象高频率创建且可复用
• 支持并发又能保护系统
• 维护、共享有限的资源
如何实现对象池?
• 开源实现:Apache Commons Pool
• Netty 轻量级对象池实现 ty.util.Recycler
怎么从堆外内存切换堆内使用?
• 方法 1:参数设置
ty.noPreferDirect = true;
• 方法 2:传入构造参数false
ServerBootstrap serverBootStrap = new ServerBootstrap();
UnpooledByteBufAllocator unpooledByteBufAllocator = new UnpooledByteBufAllocator( false );
serverBootStrap.childOption(ChannelOption.ALLOCATOR, unpooledByteBufAllocator)
堆外内存的分配?
ByteBuffer.allocateDirect(initialCapacity)