蜗牛大师

吴庆龙的学习笔记

导航

TLAB 是什么?

全称是 Thread Local Allocation Buffer,即线程本地分配缓存,是一个线程专用的内存分配区域。
 

一、Java对象的内存分配过程如何保证线程安全的?

因为堆是线程之间共享的,如果在并发场景中,两个线程先后把对象的引用指向了同一个内存区域,怎么办?
 
为了解决这个并发问题,对象的内存分配过程就必须进行同步控制,但是,无论使用哪种方案(有可能是CAS),都会影响内存的分配效率。然而对于 Java 来说对象的分配是高频操作。
 
由此 HotSpot 虚拟机采用了这个方案:每个线程在 Java 堆中预先分配一小块内存,然后在给对象分配内存的时候,直接在自己的这块”私有“内存中进行分配,当这部分用完之后,再分配新的”私有“内存。
 
这种方案被称之为 TLAB 分配。这部分 buffer 是从堆中划分出来的,但是本地线程独享的。
 

二、什么是 TLAB

TLAB 是虚拟机在内存的 eden 区划分出来的一块专用空间,是线程专属的。在启用 TLAB 的情况下,当线程被创建时,虚拟机会为每个线程分配一块 TLAB 空间,只给当前线程使用,这样每个线程都单独拥有一个空间,如果需要分配内存,就在自己的空间上分配,这样就不存在竞争的情况,可以大大提高分配效率。
 
所以说,因为有了 TLAB 技术,堆内存并不是完完全全的线程共享,其中 eden 区中还是有一部分空间是分配给线程独享的。
 
注意:这里 TLAB 的线程独享是针对于分配动作,至于读取、垃圾回收等工作是线程共享的,而且在使用上也没什么区别。
 
也就是说,虽然每个线程在初始化时都会去堆内存中申请一块 TLAB,并不是说这个 TLAB 区域的内存其他线程就完全无法访问了,其他线程的读取还是可以的,只不过无法在这个区域中分配内存而已。
 
并且,在 TLAB 分配之后,并不影响对象的移动和回收,也就是说,虽然对象刚开始可能通过 TLAB 分配内存,存放在 Eden 区,但是还是会被垃圾回收或者被移到 S 区和老年代等。
 
还有一点需要注意的是,我们说 TLAB 是在 eden 区分配的,因为 eden 区域本身就不太大,而且 TLAB 空间的内存也非常小,默认情况下仅占有整个 eden 空间的 1%。所以,必然存在一些大对象是无法在 TLAB 直接分配。遇到 TLAB 中无法分配的大对象,对象还是可能在 eden 区或者老年代等进行分配的,但是这种分配就需要进行同步控制,这也是为什么我们经常说:小的对象比大的对象分配起来更加高效。
 

三、TLAB 带来的问题

主要问题就是因为 TLAB 空间太小导致的。
 
比如一个线程的 TLAB 空间有 100KB,其中已经使用了 80KB,当需要再分配一个 30KB 的对象时,就无法直接在 TLAB 中分配,遇到这种情况时有两种处理方案:
  1. 直接在堆内存中对该对象进行内存分配。
  2. 废弃当前的 TLAB,重新申请 TLAB 空间再次进行内存分配。
方案 1 的话,如果 TLAB 只剩下 1KB 的空间了,那么后续的大多数对象都需要在堆内存中分配,方案 2 的话,有可能会有频繁的废弃 TLAB 申请 TLAB 的情况。TLAB 内存自己从堆中进行分配时也是需要并发控制的,而频繁的分配 TLAB 就失去了 TLAB 的意义了。
 
为了解决这个问题,虚拟机定义了一个 refill_waste 的值,这个值可以翻译为”最大浪费空间“。
 
当 TLAB 剩余空间不足时,
  1. 若请求分配的内存大于 refill_waste,会选择在堆内存中分配。
  2. 若请求分配的内存小于 refill_waste,会选择废弃当前的 TLAB,重新创建 TLAB 进行对象内存分配。
前面的例子中,TLAB总空间100KB,使用了80KB,剩余20KB,如果设置的refill_waste的值为25KB,那么如果新对象的内存大于25KB,则直接堆内存分配,如果小于25KB,则会废弃掉之前的那个TLAB,重新分配一个TLAB空间,给新对象分配内存。
 

四、相关参数

主要有三个参数:
  1. -XX:+/-UseTLAB 用来控制是否开启 TLAB。
  2. -XX:TLABWasteTargetPercent 设置 TLAB 空间占用 Eden 区的百分比大小,默认是 1%。
  3. -XX:-ResizeTLAB 禁用自动调整 TLAB 的大小。默认情况下,TLAB的空间会在运行时不断调整,使系统达到最佳的运行状态。
  4. -XX:TLABSize 手动指定 TLAB 的大小。
  5. -XX:TLABRefillWasteFraction 调整 refill_waste 参数,默认是64,表示使用 1/64 的 TALB 空间作为 refill_waste 的值。
  6. -XX:+PrintTLAB 跟踪 TLAB 的使用情况。
 
 
 

posted on 2021-03-26 16:56  蜗牛大师  阅读(1925)  评论(1编辑  收藏  举报