• Netty内存池源码三 (SizeClasses 前情预热)


    Netty-内存池源码三 (SizeClasses 前情预热)

    内存池核心类如下:

    • PooledByteBufAllocator
    • PooledUnsafeDirectByteBuf
    • PooledUnsafeDirectByteBuf
    • PoolThreadCache
    • MemoryRegionCache
    • PoolArena
    • SizeClasses 本期介绍
    • PoolChunk
    • LongPriorityQueue
    • LongLongHashMap
    • PoolSubpage

    上一期介绍了【PooledByteBufAllocator】类,从中可知它又将 内存分配的工作 交给了 【PoolArena】类

    若要分析 【PoolArena】 首先要分析其父类 【SizeClasses】。

    jemalloc3中 是没有【SizeClasses】类的, 而jemalloc4 相较于 jemalloc3 最大的提升是进一步优化内存碎片的问题, 这也是【SizeClasses】的由来。

    在分析【SizeClasses】之前,我们需要对Netty中的 内存规格进行简单的讲解。

    jemalloc3中,对内存规格的划分如下图:

    从中可发现,在Small级别的内存分配中会存在大量的内存碎片,比如 某业务要使用 1025B的内存,按照jemalloc3算法就会申请 2048B的 内存块, 这就会导致50%的内存碎片。

    jemalloc4中,对内存规格的划分如下图:

    从上图可看到, 当 某业务要使用1025B的内存时,jemalloc4算法会申请1280B 的内存块,这就大大减少了内存碎片。 同样也可以看出,jemalloc4取消了 Tiny级别的内存规格。

    SizeClasses】 该类的主要工作就是 按照 chunkSize 16MB 划分成了 4张表, 其实完全可以把它当作成一个虚拟的数据库,里面存在 4张表

    • sizeClasses 总表 , 维护着 各个内存规格的详细信息
    • sizeIdx2sizeTab 维护着 index 和 size的关系
    • pageIdx2sizeTab 维护着 pageSize 倍数的内存规格表
    • size2idxTab 维护着小于等于 4KB(4096) 规格的表

    SizeClasses】类大致结构如下图:

    sizeClasses

    该表维护了一个二维数组 ,具体如下:

    index log2Group log2Delta nDelta isMultiPageSize isSubPage log2DeltaLookup size(虚) Unit
    0 4 4 0 0 1 4 16
    1 4 4 1 0 1 4 32
    2 4 4 2 0 1 4 48
    3 4 4 3 0 1 4 64
    4 6 4 1 0 1 4 80
    5 6 4 2 0 1 4 96
    6 6 4 3 0 1 4 112
    7 6 4 4 0 1 4 128
    8 7 5 1 0 1 5 160
    9 7 5 2 0 1 5 192
    10 7 5 3 0 1 5 224
    11 7 5 4 0 1 5 256
    12 8 6 1 0 1 6 320
    13 8 6 2 0 1 6 384
    14 8 6 3 0 1 6 448
    15 8 6 4 0 1 6 512
    16 9 7 1 0 1 7 640
    17 9 7 2 0 1 7 768
    18 9 7 3 0 1 7 896
    19 9 7 4 0 1 7 1024
    20 10 8 1 0 1 8 1280
    21 10 8 2 0 1 8 1536
    22 10 8 3 0 1 8 1792
    23 10 8 4 0 1 8 2048
    24 11 9 1 0 1 9 2560
    25 11 9 2 0 1 9 3072
    26 11 9 3 0 1 9 3584
    27 11 9 4 0 1 9 4096 4KB
    28 12 10 1 0 1 0 5120
    29 12 10 2 0 1 0 6144
    30 12 10 3 0 1 0 7168
    31 12 10 4 1 1 0 8192 8KB
    32 13 11 1 0 1 0 10240 10KB
    33 13 11 2 0 1 0 12288 12KB
    34 13 11 3 0 1 0 14336 14KB
    35 13 11 4 1 1 0 16384 16KB
    36 14 12 1 0 1 0 20480 20KB
    37 14 12 2 1 1 0 24576 24KB
    38 14 12 3 0 1 0 28672 28KB
    39 14 12 4 1 0 0 32768 32KB
    40 15 13 1 1 0 0 40960 40KB
    41 15 13 2 1 0 0 49152 48KB
    42 15 13 3 1 0 0 57344 56KB
    43 15 13 4 1 0 0 65536 64KB
    44 16 14 1 1 0 0 81920 80KB
    45 16 14 2 1 0 0 98304 96KB
    46 16 14 3 1 0 0 114688 112KB
    47 16 14 4 1 0 0 131072 128KB
    48 17 15 1 1 0 0 163840 160KB
    49 17 15 2 1 0 0 196608 192KB
    50 17 15 3 1 0 0 229376 224KB
    51 17 15 3 1 0 0 262144 256KB
    52 18 16 1 1 0 0 327680 320KB
    53 18 16 2 1 0 0 393216 384KB
    54 18 16 3 1 0 0 458752 448KB
    55 18 16 4 1 0 0 524288 512KB
    56 19 17 1 1 0 0 655360 640KB
    57 19 17 2 1 0 0 786432 768KB
    58 19 17 3 1 0 0 917504 896KB
    59 19 17 4 1 0 0 1048576 1.0MB
    60 20 18 1 1 0 0 1310720 1.25MB
    61 20 18 2 1 0 0 1572864 1.5MB
    62 20 18 3 1 0 0 1835008 1.75MB
    63 20 18 4 1 0 0 2097152 2MB
    64 21 19 1 1 0 0 2621440 2.5MB
    65 21 19 2 1 0 0 3145728 3MB
    66 21 19 3 1 0 0 3670016 3.5MB
    67 21 19 4 1 0 0 4194304 4MB
    68 22 20 1 1 0 0 5242880 5MB
    69 22 20 2 1 0 0 6291456 6MB
    70 22 20 3 1 0 0 7340030 7MB
    71 22 20 4 1 0 0 8388608 8MB
    72 23 21 1 1 0 0 10485760 10MB
    73 23 21 2 1 0 0 12582912 12MB
    74 23 21 3 1 0 0 14680064 14MB
    75 23 21 4 1 0 0 16777216 16MB

    从上表中可知,数组长度 76。每一列表示的含义如下:

    • index: 由 0 开始的自增序列号,表示每个 size 类型的索引。

    • log2Group: 表示每个 size 它所对应的组。

      以每 4 行为一组,一共有 19 组。

      第 0 组比较特殊 值为4。

      因此,我们应该从第 1 组开始,起始值为 6,每组的 log2Group 是在上一组的值 +1。

    • log2Delta: 表示当前序号所对应的 size 和前一个序号所对应的 size 的差值的 log2 的值。

      例如: index=6 对应的 size = 112,index=7 对应的 size= 128,因此 index=7 的 log2Delta(7) = log2(128-112)=4。

      规律:其实 log2Delta=log2Group-2。

    • nDelta: 表示组内增量的倍数。第 0 组也是比较特殊,nDelta 是从 0 开始 + 1。而其余组是从 1 开始 +1

    • isMultiPageSize: 表示当前 size 是否是 pageSize(默认值: 8192) 的整数倍。后续会把 isMultiPageSize=1 的行单独整理成一张表,你会发现有 40 个 isMultiPageSize=1 的行。

    • isSubPage: 表示当前 size 是否为一个 subPage 类型,jemalloc4 会根据这个值采取不同的内存分配策略。

    • log2DeltaLookup: 当 index<=27 时,其值和 log2Delta 相等,当index>27,其值为 0。

    jemalloc4 求 SIZE 的公式:

    公式1: size = (1 << log2Group) + nDelta (1<<log2Delta)*

    公式2: log2Group = log2Delta + 2

    公式2带入公式1可得:

    ​ **size = (1 << log2Delta + 2) + nDelta * (1<<log2Delta) **

    进一步 整理简化 最终可得出:

    size = (1<< log2Delta) * (nDelta + 4)

    由最终整理后的公式 size = (1<< log2Delta) * (nDelta + 4) 可知两个结论:

    结论一: 每一组中每行的log2Delta是相同的, 而nDelta的范围是 [1,4] ,那么 nDelta +4 的取值范围就是 [5,8],也就是说同一组中的 size是按照 5,6,7,8 倍来增长的。 (除第一组以外)

    结论二:每一组的最后一个的 nDelta + 4 = 4 + 4 = 8 => 1<<3,那么 size = 1<< log2Delta+3 。 也就是说除了第一组外, 其它每一组的最后一行 size = 1 << log2Delta

    sizeIdx2sizeTab

    维护16MB以内所有规格 index 和 size 关系的一张表

    index size(虚) Unit
    0 16
    1 32
    2 48
    3 64
    4 80
    5 96
    6 112
    7 128
    8 160
    9 192
    10 224
    11 256
    12 320
    13 384
    14 448
    15 512
    16 640
    17 768
    18 896
    19 1024
    20 1280
    21 1536
    22 1792
    23 2048
    24 2560
    25 3072
    26 3584
    27 4096 4KB
    28 5120
    29 6144
    30 7168
    31 8192 8KB
    32 10240 10KB
    33 12288 12KB
    34 14336 14KB
    35 16384 16KB
    36 20480 20KB
    37 24576 24KB
    38 28672 28KB
    39 32768 32KB
    40 40960 40KB
    41 49152 48KB
    42 57344 56KB
    43 65536 64KB
    44 81920 80KB
    45 98304 96KB
    46 114688 112KB
    47 131072 128KB
    48 163840 160KB
    49 196608 192KB
    50 229376 224KB
    51 262144 256KB
    52 327680 320KB
    53 393216 384KB
    54 458752 448KB
    55 524288 512KB
    56 655360 640KB
    57 786432 768KB
    58 917504 896KB
    59 1048576 1.0MB
    60 1310720 1.25MB
    61 1572864 1.5MB
    62 1835008 1.75MB
    63 2097152 2MB
    64 2621440 2.5MB
    65 3145728 3MB
    66 3670016 3.5MB
    67 4194304 4MB
    68 5242880 5MB
    69 6291456 6MB
    70 7340030 7MB
    71 8388608 8MB
    72 10485760 10MB
    73 12582912 12MB
    74 14680064 14MB
    75 16777216 16MB

    pageIdx2sizeTab

    isMultiPageSize 字段为1的行,会组合成 这张表。 也就该表都是 页(8KB) 的倍数的 size规格。

    pageIndex index(虚) isMultiPageSize(虚) num of page(虚) size Unit
    0 31 1 1 8192 8KB
    1 35 1 2 16384 16KB
    2 37 1 3 24576 24KB
    3 39 1 4 32768 32KB
    4 40 1 5 40960 40KB
    5 41 1 6 49152 48KB
    6 42 1 7 57344 56KB
    7 43 1 8 65536 64KB
    8 44 1 10 81920 80KB
    9 45 1 12 98304 96KB
    10 46 1 14 114688 112KB
    11 47 1 16 131072 128KB
    12 48 1 20 163840 160KB
    13 49 1 24 196608 192KB
    14 50 1 28 229376 224KB
    15 51 1 32 262144 256KB
    16 52 1 40 327680 320KB
    17 53 1 48 393216 384KB
    18 54 1 56 458752 448KB
    19 55 1 64 524288 512KB
    20 56 1 80 655360 640KB
    21 57 1 96 786432 768KB
    22 58 1 112 917504 896KB
    23 59 1 128 1048576 1.0MB
    24 60 1 160 1310720 1.25MB
    25 61 1 192 1572864 1.5MB
    26 62 1 224 1835008 1.75MB
    27 63 1 256 2097152 2MB
    28 64 1 320 2621440 2.5MB
    29 65 1 384 3145728 3MB
    30 66 1 448 3670016 3.5MB
    31 67 1 512 4194304 4MB
    32 68 1 640 5242880 5MB
    33 69 1 768 6291456 6MB
    34 70 1 896 7340030 7MB
    35 71 1 1024 8388608 8MB
    36 72 1 1280 10485760 10MB
    37 73 1 1536 12582912 12MB
    38 74 1 1792 14680064 14MB
    39 75 1 2048 16777216 16MB

    size2idxTab

    size 小于等于 4KB (4096) 的 规格, 做一个细致的划分, 以16B为递增 增量。

    由于里面行数太多,这里不展示全部的了,大致如下图:

    由于图表的原因 导致篇幅太长,具体的【SizeClasses】源码分析会到下期文章分析。

    万般皆下品,唯有读书高!
  • 相关阅读:
    python基础
    用纯css改变下拉列表select框的默认样式兼容ie9需要用js
    如何阻止360浏览器backspace键的默认快捷键
    js判断undefined类型,undefined,null, 的区别详细解析
    jquery事件日历插件e-calendar 的修改
    each和for一起使用
    2019.9.24 网络ip小知识
    数据库SQL开始学习_5
    2019.9.22 java小知识
    数据库SQL开始学习_4
  • 原文地址:https://www.cnblogs.com/s686zhou/p/15705446.html
Copyright © 2020-2023  润新知