1.什么是TLAB
新对象都是在Eden区分配空间,这块空间是在多线程间共享的。那么考虑一下,多线程是可能同时创建新对象的,这时候必然需要一种同步机制。使用队列?或者通过互斥?这些方式确实都可以。不过,我们还有一种更好的方式,TLAB,它全称是thread local allocation buffer,这是eden区里的一块空间。每个线程都有它自己的tlab,因此,只要对象分配是发生在tlab里面,这时候就不需要进行同步控制。
其实分配的时候,是让每个线程拥有了私有的分配指针,实际的对象存储的地方,依然是公共可访问的。
2.TLAB满了之后
// ThreadLocalAllocBuffer: a descriptor for thread-local storage used by
// the threads for allocation.
// It is thread-private at any time, but maybe multiplexed over
// time across multiple threads. The park()/unpark() pair is
// used to make it avaiable for such multiplexing.
class ThreadLocalAllocBuffer: public CHeapObj<mtThread> {
friend class VMStructs;
private:
HeapWord* _start; // address of TLAB
HeapWord* _top; // address after last allocation
HeapWord* _pf_top; // allocation prefetch watermark
HeapWord* _end; // allocation end (excluding alignment_reserve)
size_t _desired_size; // desired size (including alignment_reserve)
size_t _refill_waste_limit; // hold onto tlab if free() is larger than this
大概的结构就是它占了一块空间,_start和_end标记这块空间,开始的时候_top就在_start的位置, 每次分配对象,直到碰撞到_end.
_desired_size是分配的tlab的大小。
_refill_waste_limit是说最大可以浪费的空间。
说明下这个的作用。先看下这段。
If the remaining space in the TLAB is larger than this amount, and an allocation is requested that is too large to be allocated in the TLAB, then the allocation is done directly in Eden and the TLAB is not retired.
If the remaining space is less than refill_waste_limit then the TLAB is retired, a new TLAB is allocated, and the object allocation is attempted in the new TLAB。
举个栗子。
Case-1:_refill_waste_limit=4k, 剩余空间6k,这时候要分配一个新对象8k,这时候会直接在eden区分配,这块tlab后续继续使用。
Case-2:_refill_waste_limit=4k, 剩余空间2k,这时候要分配一个新对象5k,这时候会分配一块新的tlab,并尝试在这块空间分配空间给新对象,原来的tlab就retire了(交给eden管理了吧),浪费了2k。
3.分配大对象
默认情况,tlab的大小是动态调整的。Eden区的大小,线程数量,对象的分配速度,这些因素都会影响tlab大小的调整。那么当要分配一个大对象,它会直接分配在eden区(如果特别大就当old generation),在tlab外面分配就意味着需要进行同步控制,那么应对的方案也有2种。
3.1调整tlab的大小
-XX:MinTLABSize=4k(举个栗子,最小的tlab大小)
在jdk8里面,默认值是2048 bytes
-XX:TLABSize (tlab的初始大小, 默认0)
3.2换成小对象
4.常见相关jvm参数
打印gc日志的同时打印tlab信息。
-Xloggc:D:\tmp\logs\2019\05\local-gc.log
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-XX:+PrintTLAB
参考:
https://blogs.oracle.com/jonthecollector/the-real-thing
https://dzone.com/articles/thread-local-allocation-buffers
欢迎留言讨论并关注微信公众号:假程序员