1. TLAB(Thread Local Allocation Buffer)란 무엇인가?
TLAB은 Thread Local Allocation Buffer의 약자로, 각 Java 스레드가 객체를 빠르게 할당할 수 있도록 Eden 영역 안에 미리 확보해 두는 작은 버퍼다. 여러 스레드가 동시에 Heap에 객체를 할당하면 동기화 비용이 발생할 수 있는데, TLAB을 사용하면 각 스레드가 자기 버퍼 안에서 포인터만 증가시키는 방식으로 객체를 할당할 수 있어 비용을 줄일 수 있다.
- Heap 메모리에 새로운 객체가 생성될 때 TLAB이 활성화되어 있고, 객체가 현재 TLAB에 들어갈 만큼 작다면 우선 해당 스레드의 TLAB에 할당된다.
- TLAB은 Eden 영역에 존재한다. 따라서 TLAB을 사용하면 Eden 영역의 일부를 스레드별 버퍼로 나누어 쓰게 되지만, 객체 생성 시 성능상 이점을 얻을 수 있다.
- 각 스레드는 빠른 메모리 할당을 위해 자신만의 TLAB을 가진다.
- TLAB은 필요할 때 스레드에 할당되거나 다시 채워진다(refill).
- 따라서 동시에 동작하는 스레드가 많을수록 TLAB으로 예약되는 전체 공간도 증가할 수 있다.
- TLAB을 사용하려면
-XX:+UseTLAB옵션을 사용한다. 일반적인 HotSpot JVM에서는 기본적으로 활성화되어 있는 경우가 많다. - TLAB 크기를 직접 지정하려면
-XX:TLABSize=<size>옵션을 사용한다. 값을 지정하지 않거나 기본값을 사용하면 JVM이 실행 상황에 맞게 조절한다.
TLAB에 남은 공간보다 큰 객체를 할당해야 하거나, TLAB을 새로 채우는 과정에서 조건이 맞지 않으면 일반적인 Eden 할당 경로를 사용한다. 로그에 보이는 slow allocs는 이런 느린 경로의 할당 횟수를 이해하는 데 참고할 수 있다.
2. PLAB(Promotion Local Allocation Buffer)란 무엇인가?
PLAB은 Promotion Local Allocation Buffer의 약자로, GC 중 객체를 다른 영역으로 복사하거나 승격(promotion)할 때 사용하는 스레드별 할당 버퍼다. TLAB이 애플리케이션 스레드의 일반 객체 할당을 빠르게 하기 위한 장치라면, PLAB은 GC 작업 스레드가 객체를 복사하는 과정에서 동기화 비용을 줄이기 위한 장치라고 볼 수 있다.
- GC에서 객체를 복사하거나 세대 간 승격하는 동안 사용된다.
- GC 작업을 수행하는 각 스레드가 로컬 버퍼를 사용해 할당 경합을 줄인다.
- PLAB 크기도 JVM의 정책과 GC 동작에 따라 조절될 수 있다.
3. 옵션
3-1. -XX:+PrintTLAB
-XX:+PrintTLAB 옵션을 사용하면 TLAB 할당과 관련된 로그를 확인할 수 있다. 다만 JDK 버전에 따라 지원 여부나 출력 형식이 다를 수 있으며, 최신 JDK에서는 통합 로깅 옵션인 -Xlog:gc+tlab=trace 형태를 사용하는 경우가 많다.
아래 출력에서는 스레드별 TLAB 크기, refill 횟수, 낭비된 공간, 느린 할당 횟수 등을 확인할 수 있다. 예를 들어 refills는 TLAB을 다시 채운 횟수이고, waste는 TLAB 안에서 사용되지 못하고 남은 공간의 비율 또는 크기를 나타낸다.
TLAB: gc thread: 0x00007f12d444d000 [id: 9220] desired_size: 5253KB slow allocs: 0 refill waste: 84048B alloc: 1.00000 262656KB refills: 1 waste 96.1% gc: 5167296B slow: 0B fast: 0B TLAB: gc thread: 0x00007f12d444c800 [id: 9218] desired_size: 5253KB slow allocs: 0 refill waste: 84048B alloc: 1.00000 262656KB refills: 1 waste 96.1% gc: 5167256B slow: 0B fast: 0B TLAB: gc thread: 0x00007f12d444a000 [id: 9215] desired_size: 5253KB slow allocs: 0 refill waste: 84048B alloc: 1.00000 262656KB refills: 1 waste 96.0% gc: 5166080B slow: 0B fast: 0B TLAB: gc thread: 0x00007f12d4448000 [id: 9212] desired_size: 5253KB slow allocs: 0 refill waste: 84048B alloc: 1.00000 262656KB refills: 1 waste 96.7% gc: 5200080B slow: 0B fast: 0B TLAB: gc thread: 0x00007f12d4447000 [id: 9210] desired_size: 5253KB slow allocs: 0 refill waste: 84048B alloc: 1.00000 262656KB refills: 1 waste 96.3% gc: 5179496B slow: 0B fast: 0B (생략) TLAB totals: thrds: 33 refills: 39 max: 6 slow allocs: 0 max 0 waste: 78.8% gc: 165378464B max: 5378928B slow: 736B max: 704B fast: 0B max: 0B TLAB totals: thrds: 33 refills: 39 max: 6 slow allocs: 0 max 0 waste: 78.8% gc: 165245312B max: 5378928B slow: 368B max: 328B fast: 0B max: 0B TLAB totals: thrds: 37 refills: 84 max: 9 slow allocs: 4 max 1 waste: 21.3% gc: 41685120B max: 5379120B slow: 202264B max: 45128B fast: 0B max: 0B TLAB totals: thrds: 35 refills: 129 max: 12 slow allocs: 8 max 2 waste: 16.3% gc: 33513720B max: 5344256B slow: 421456B max: 88832B fast: 0B max: 0B TLAB totals: thrds: 44 refills: 173 max: 16 slow allocs: 35 max 8 waste: 24.0% gc: 52984776B max: 5333392B slow: 508152B max: 62944B fast: 0B max: 0B TLAB totals: thrds: 41 refills: 240 max: 22 slow allocs: 60 max 5 waste: 13.4% gc: 27595256B max: 2688952B slow: 761752B max: 112192B fast: 0B max: 0B TLAB totals: thrds: 34 refills: 322 max: 31 slow allocs: 65 max 7 waste: 9.6% gc: 20742400B max: 1740696B slow: 822424B max: 130184B fast: 0B max: 0B TLAB totals: thrds: 41 refills: 409 max: 32 slow allocs: 155 max 11 waste: 7.0% gc: 13045448B max: 1591360B slow: 619808B max: 90904B fast: 0B max: 0B TLAB totals: thrds: 41 refills: 539 max: 40 slow allocs: 390 max 64 waste: 5.7% gc: 11271520B max: 1591840B slow: 1026104B max: 271928B fast: 0B max: 0B TLAB totals: thrds: 45 refills: 656 max: 44 slow allocs: 523 max 75 waste: 4.2% gc: 8258552B max: 973136B slow: 790816B max: 128424B fast: 0B max: 0B TLAB totals: thrds: 37 refills: 721 max: 48 slow allocs: 690 max 70 waste: 2.2% gc: 3771880B max: 417680B slow: 905232B max: 222544B fast: 0B max: 0B TLAB totals: thrds: 45 refills: 812 max: 49 slow allocs: 682 max 79 waste: 3.6% gc: 7134032B max: 973976B slow: 717656B max: 134944B fast: 0B max: 0B TLAB totals: thrds: 40 refills: 692 max: 39 slow allocs: 733 max 67 waste: 1.6% gc: 1954992B max: 315616B slow: 655208B max: 175088B fast: 0B max: 0B TLAB totals: thrds: 42
3-2. 확인 방법
TLAB이 실제로 사용되는지 확인하려면 간단히 객체를 많이 생성하는 프로그램을 실행한 뒤 위 옵션을 켜고 로그를 보면 된다. 로그에서 TLAB totals, refills, slow allocs, waste 값이 어떻게 변하는지 확인하면 TLAB이 객체 할당에 어떤 영향을 주는지 감을 잡을 수 있다.