bigywater.tech
Java · 237

TLAB:线程如何快速分配小对象

每个线程有一块自己的分配缓冲(TLAB),分配小对象只是移动一个指针,不需要加锁。这篇用真实的基准和 TLAB 日志验证它的收益、大小怎么自适应,以及手工设置会发生什么。

596 vs 3
8 个线程小对象分配吞吐(M 对象/秒):TLAB / 关闭 TLAB
512 → 421 KB
GC 时记录的 TLAB desired_size 中位:1 个分配线程 → 16 个分配线程
512 KB
这个环境里 -XX:TLABSize 的上限

有 TLAB 与没有 TLAB

实测 · 本机执行输出
  默认(TLAB)       1 个线程,每线程分配 5000 万个 16 字节对象:总吞吐 194 M 对象/秒
  -XX:-UseTLAB   1 个线程,每线程分配 5000 万个 16 字节对象:总吞吐 13 M 对象/秒
  默认(TLAB)       4 个线程,每线程分配 5000 万个 16 字节对象:总吞吐 559 M 对象/秒
  -XX:-UseTLAB   4 个线程,每线程分配 5000 万个 16 字节对象:总吞吐 8 M 对象/秒
  默认(TLAB)       8 个线程,每线程分配 5000 万个 16 字节对象:总吞吐 596 M 对象/秒
  -XX:-UseTLAB   8 个线程,每线程分配 5000 万个 16 字节对象:总吞吐 3 M 对象/秒

对象大小与 TLAB

实测 · 本机执行输出
  byte[      64]: 2000000 次分配,每次        10 ns,每 KB  165.61 ns
  byte[    1024]: 1048576 次分配,每次        97 ns,每 KB   96.91 ns
  byte[   16384]:   65536 次分配,每次       746 ns,每 KB   46.60 ns
  byte[  262144]:    4096 次分配,每次      4392 ns,每 KB   17.16 ns
  byte[ 4194304]:     256 次分配,每次     50723 ns,每 KB   12.38 ns
  日志里 TLAB「fill」事件(TLAB 被重新分配)共 4099 次;GC 时记录的 desired_size(KB):最小 245、最大 512

自适应的 TLAB 大小

实测 · 本机执行输出
   1 个分配线程:TLAB fill 事件共 1885 次(有 fill 的线程 6 个,每个线程 fill 次数中位 1);GC 时记录的 desired_size(KB)中位 512、最小 245、最大 512
   4 个分配线程:TLAB fill 事件共 7791 次(有 fill 的线程 8 个,每个线程 fill 次数中位 970);GC 时记录的 desired_size(KB)中位 512、最小 245、最大 512
  16 个分配线程:TLAB fill 事件共 50075 次(有 fill 的线程 21 个,每个线程 fill 次数中位 3120);GC 时记录的 desired_size(KB)中位 421、最小 235、最大 512

手工设置 TLABSize

实测 · 本机执行输出
  默认                                 4 个分配线程:TLAB fill 共 23148 次;GC 时 desired_size(KB)中位 512;吞吐 559 M 对象/秒
  -XX:TLABSize=64k -XX:-ResizeTLAB   4 个分配线程:TLAB fill 共 87751 次;GC 时 desired_size(KB)中位 64;吞吐 132 M 对象/秒
  -XX:TLABSize=512k -XX:-ResizeTLAB  4 个分配线程:TLAB fill 共 22077 次;GC 时 desired_size(KB)中位 512;吞吐 556 M 对象/秒
  -XX:TLABSize=4m -XX:-ResizeTLAB    JVM 没有启动:TLABSize (4194304) must be less than or equal to ergonomic TLAB maximum size (524288)

分步演示

TLAB
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / OpenJDK(Temurin 17.0.20、Homebrew 21.0.12 与 27,每篇注明实际用的版本);用 javac 编译、java 直接运行,需要第三方库时用 Maven 解析依赖;计时用 System.nanoTime,数字每次运行会有小幅抖动。JDK 21.0.12,G1、-Xms512m -Xmx512m,10 核 macOS
    • 没有验证:ZGC/Shenandoah/Parallel 下的 TLAB 行为、TLAB 浪费百分比(日志里有,没有展开)、JIT 在循环里对分配的优化(逃逸分析)——基准里特意让对象逃逸到静态数组;-XX:-UseTLAB 只是对照实验,不要用于生产;吞吐数字只表示这台机器上的相对关系
    京ICP备2026067502号-1京公网安备11010502063487号