arena_get2 是 ptmalloc2 中线程无法从 TLS 获取到 Arena 时,用来“分配”或“创建”一个可用 Arena 的决策函数。它就像一个调度员:先看有没有“空闲”的,没有就“回收利用”,实在不行才“新建”。
核心决策逻辑
它通过一个层级化的策略来平衡性能与内存开销:
-
首选:回收空闲 Arena (
get_free_list):优先从全局空闲链表中“捡”一个现成的,这是最经济的做法。 -
次选:复用忙碌 Arena (
reused_arena):如果没有空闲的,就尝试复用其他线程正在使用但当前未被锁定的 Arena。 -
最后:创建新 Arena (
_int_new_arena):只有在复用也失败,且当前 Arena 总数未达到上限时,才真正创建一个全新的。
关键参数与上限判定
-
size:提示新 Arena 初始需要的内存大小,用于指导mmap分配堆段。 -
avoid_arena:指示“避免复用”的特定 Arena,通常在分配失败重试时使用,防止死循环。 -
上限判定 (
narenas_limit):通过原子操作检查narenas是否超过上限。如果未超限,则走_int_new_arena路径;否则调用reused_arena。上限通常由 CPU 核心数或M_ARENA_MAX环境变量决定。
策略对比
| 策略 | 调用函数 | 触发条件 | 特点 |
|---|---|---|---|
| 回收空闲 | get_free_list | free_list 非空 | 最快,无竞争 |
| 复用忙碌 | reused_arena | 无空闲,且达上限 | 尝试“捡漏”,可能阻塞 |
| 创建新建 | _int_new_arena | 未达上限 | 开销 |
arena_get2 是 ptmalloc2 中当线程无法从 TLS 获取到 Arena 时的“兜底分配器”。它的核心使命是在并发环境下,安全且高效地为线程“找”一个可用的 Arena,其实现遵循一个明确的三优先级策略。
核心决策逻辑:三级瀑布式回退
这个函数严格按顺序尝试三种方案,优先选择开销最小的:
-
首选:回收空闲 Arena:调用
get_free_list(),直接从全局空闲链表free_list中“捡”一个现成的 Arena。这是最经济的做法,因为不需要创建新的堆段。 -
次选:复用忙碌 Arena:如果空闲链表为空,调用
reused_arena()。它会乐观地尝试用trylock快速锁定一个未被使用的 Arena,如果所有 Arena 都在忙,就退而求其次,阻塞等待一个特定的 Arena。这避免了创建新 Arena 的开销。 -
最后:创建新 Arena:只有在复用也失败,且当前 Arena 总数未达到上限时,才调用
_int_new_arena(size)通过mmap真正创建一个全新的 Arena。这是开销最大的路径。
关键实现细节
-
上限控制 (
narenas_limit):在决定是否创建新 Arena 时,会检查当前总数narenas。上限通常由 CPU 核心数或M_ARENA_MAX环境变量决定。代码中有一个经典判断n <= narenas_limit - 1,利用无符号整数下溢的特性来处理边界情况。 -
避免自锁 (
avoid_arena):函数接收一个avoid_arena参数,指示应避免复用该特定 Arena。这主要用于分配失败后的重试场景,防止线程在已锁定的 Arena 上再次尝试加锁,从而引发死锁。
策略对比
| 策略 | 触发条件 | 开销 |
|---|---|---|
| 回收空闲 | free_list 非空 | 最低 |
| 复用忙碌 | 无空闲,且达上限 | 中等(可能阻塞) |
| 创建新建 | 未达上限 | 最高 |

423

被折叠的 条评论
为什么被折叠?



