系列文章目录
1. Netty网络应用基础
2. Java I/O
3. IO/模型
4. 网络应用编解码
5. Netty Pipeline
6. Netty EventLoopGroup&EventLoop
7. Netty ThreadLocal&FastThreadLocal
8. Netty Future&Promise
9. Netty内存管理–(旧)PoolChunk&伙伴分配
10. Netty内存管理–内存池空间规格化SizeClasses
11. Netty内存管理–PoolChunk&PoolSubPage
12. Netty内存管理–内存池PoolArena
13. Netty内存管理–内存分配器PooledByteBufAllocator
14. Netty ObjectPool
写在前面
网络通信中,接收端通常需要多层解码,最终在应用层解码后才能得到业务层可处理的message。Netty需要缓存接收到的网络数据和待发送的网络数据,缓存发送/解码完成后就可以释放。其中对缓存的获取和释放频次高;通过系统调用获取内存本身比较耗时;高频的缓存释放对Java GC产生压力;随之带来的是GC压力。而GC过程中可能会导致STW(Stop The Wold)现象,进而影响响应延迟。因此需要对缓存的分配和释放做必要的管理。提高内存利用率。
从4.1.52.Final开始, Netty删除了TinyPagePool, 以减少内部碎片。官方提供的原因是由于jmelloc 4.x的更新, Netty随后也进行了必要的更新。参见Netty Release Note
本篇的page管理基于伙伴算法分配, 为4.1.52.Final之前版本使用,在此仅做简单探讨。
一、内存规格化
名称 | 尺寸 | 分配位置 | 分配单位 |
---|---|---|---|
Normal | [8K, 16M] | Chunk | Page |
Tiny | [496B, 4096B] | Page | SubPage |
Small | (0, 496B) | Page | SubPage |
Huge | 16M+ | 不复用 | 不复用 |
最终形成两级颗粒度, 从Chunk中划分Page, 从Page中划分SubPage。本篇咱们先聚焦在Page级别的分配。
二、Chunk中Page管理
Chunk默认向OS申请16M的连续内存, 按照伙伴算法的划分方式, 直到每个伙伴的空间大小为一个page。整个划分过程结束后形成一颗满二叉树, 后续的空间管理基于该二叉树完成;
1.二叉树表示
Netty使用两个数组来memoryMap和depthMap表示该二叉树。memoryMap和depthMap, 下标都表示内存块编号,数值标识内存块层级。至于空间大小, 直接基于节点层级计算即可。
数值内容 | 含义 |
---|---|
memoryMap[id] = depthMap[id] | 该节点没有被分配, 初始化完成时为该状态。 |
depthMap[id] < memoryMap[id] < 最大高度(12) | 至少有一个子节点被分配,但尚未完全被分配,不能再分配该高度对应的内存,只能根据实际情况在更低层次分配内存 |
memoryMap[id] = 最大高度(12) | 该节点及其子节点已被完全分配,没有剩余空间 |
2 Page分配过程
假设现在有一个新初始化的chunk, 从中分配150K内存;
- 将150K的空间规格化, 结果为256K, 应该在第7层(每个单元的空间大小为256K);
- 遍历memoryMap, 遍历的索引分别为(1,2,4,8,16,32,64), 如下图黑框中内容为实际为遍历的节点(注意在Netty的MemoryMap和depthMap中有效索引从1开始,0是被浪费掉的);
- 结合前面的条件, memoryMap[64]这个节点可以正常分配, 将memoryMap[64]设置为12, 并关联更新父节点为左右节点中层级较小的depthMap。
memoryMap[index] | 容量单位 | 原值 | 更新后的值 |
---|---|---|---|
64 | 256K | 7 | 12 |
32 | 512K | 6 | 7 |
16 | 1M | 5 | 6 |
8 | 2M | 4 | 5 |
4 | 4M | 3 | 4 |
2 | 8M | 2 | 3 |
1 | 16M | 1 | 2 |
- 虽然申请150K, 但最终实际获得了256K也就是32个Page的内存。到这里想必你已经对伙伴分配算法的分配过程有了一个初步的理解, 目标是要做到对不同颗粒度的连续内存分配。
3 Page回收过程
作为分配的逆过程, 回收过程就相对清晰了。比如前面150K内存回收, 将起始位置offset+32个page的内容清理掉, 然后memoryMap[64]=depthMap[64], 并关联设置父节点的值为左右子节点的memoryMap中较小的那个, 回收结束。文章来源:https://www.toymoban.com/news/detail-420483.html
总结
本篇Netty中内存内存规格化,对应的管理颗粒Chuank和Page,以及Chunk中Page的分配与回收过程。Netty具体的实现中会做额外的一些优化,后续会一并总结。文章来源地址https://www.toymoban.com/news/detail-420483.html
到了这里,关于Netty内存管理--Chunk&Page的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!