每个线程有一块自己的分配缓冲(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 对象/秒
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
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
默认 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)