本地线程分配缓冲区

1.什么是线程分配缓冲区?

TLAB是JVM在堆内存的Eden区划分出来的一块专用于原始线程进行对象分配的区域。在虚拟机的TLAB功能启动的情况下,在线程初始化时,虚拟机会为每个线程分配一块TLAB空间,只给当前线程使用,如需要分配内存,在自己的TLAB上分配。

2.为什么会出现TLAB?

堆是所有线程所共享的区域,在多线程的环境下,在堆上创建对象是线程不安全的。

我们知道对象的创建过程分为三步:类加载、分配内存、初始化。如果两个线程在创建对象时,为他们分配了同一块内存区域,那必然会出现线程安全问题。

想要解决这个问题有两种方案:

①对内存分配的动作进行同步处理,但是这种方式是非常影响程序的性能和执行效率的。

②把内存分配的动作按照线程划分在不同的空间之中进行,即给每个线程在Java堆中都预先分配一小块私有内存,也就是本地线程分配缓冲区(Thread Local Allocation Buffer,TLAB)

3.理解”私有“

”私有“只是指在”内存分配“上是线程独享的,也就是线程只能在自己的TLAB上给对象分配内存空间,但是仍然可以读取其他线程的TLAB,Minor GC也是针对于整个Eden区来说的。

TLAB默认情况下处于启用状态,可以随时使用-XX:-UseTLAB调整标志将其禁用

4.TLAB的工作原理

TLAB的数据结构:
class ThreadLocalAllocBuffer: public CHeapObj<mtThread> {
  HeapWord* _start;   // _start 指TLAB连续内存起始地址。
  HeapWord* _top;     // _top 指TLAB当前分配到的地址。
  HeapWord* _pf_top;  // allocation prefetch watermark
  HeapWord* _end;     // _end 指TLAB连续内存截止地址。alignment_reserve)
  size_t    _desired_size; // _desired_size 是指TLAB的内存大小
  size_t    _refill_waste_limit; // _refill_waste_limit 是指最大的浪费空间
  .....................省略......................
}

可以看到TLAB的数据结构中维护了多个指针,线程只能在自己TLAB的start和end指针间分配对象。

eg:假设为refill_waste_limit=5KB:

1、假如当前TLAB已经分配96KB,还剩下4KB可分配,但是现在new了一个对象需要6KB的空间,显然TLAB的内存不够了,4kb<5kb这时只浪费4KB的空间,在refill_waste_limit 之内,这时可以申请一个新的TLAB空间,原先的TLAB交给Eden管理。

2、假如当前TLAB已经分配90KB,还剩下10KB,现在new了一个对象需要11KB,显然TLAB的内存不够了,这时就不能简单的抛弃当前TLAB,这11KB会被安排到Eden区进行申请。

5.TLAB是如何分配的?

1) obj_size + tlab_top <= tlab_end,直接在TLAB空间分配对象。

2) obj_size + tlab_top >= tlab_end && tlab_free > tlab_refill_waste_limit,对象不在TLAB分配,在Eden区分配。(tlab_free:剩余的内存空间,tlab_refill_waste_limit:允许浪费的内存空间)<----总结:tlab剩余可用空间>tlab可浪费空间,当前线程不能丢弃当前TLAB,本次申请交由Eden区分配空间

3) obj_size + tlab_top >= tlab_end && tlab_free < _refill_waste_limit,重新分配一块TLAB空间,在新的TLAB中分配对象。<----总结:tlab剩余可用空间<tlab可浪费空间,在当前允许可浪费空间内,重新申请一个新TLAB空间,原TLAB交给Eden(原TLAB的生命周期停止了)

6.如何调整TLAB的大小?

TLAB都不大,默认情况下仅占有整个Eden空间的1%,因此大型对象无法在TLAB内进行分配。大型对象必须直接从堆上分配,那就需要同步,所以说小的对象比大的对象分配起来更加高效。

默认情况下,TLAB的大小由三个因素决定:应用程序的线程数、Eden空间的大小和以及线程分配率。

  • -XX:+UseTLAB 启用TLAB(默认是启用的)

  • -XX:TLABsize=N 可以显示调整TLAB的大小(默认是0),这个标志只能设置TLAB的初始大小,如果-XX:+ResizeTLAB开启了,TLAB大小就是会随着程序的运行动态调整的

  • -XX:-ResizeTLAB 禁止系统自动调整TLAB的大小(大多数的平台上,这个参数的默认值都是true)

  • -XX:TLABRefillWasteFraction = N 设置允许空间浪费的比例 (默认64,即用1/64的TLAB空间大小作为refill_waste_limit),TLAB最大浪费空间= TLAB大小/TLABRefillWasteFraction,refill_waste也是会在程序运行期间动态调整的,来使系统的运行状态达到最优。

  • -XX:MinTLABSize=N 设置TLAB容量的最小值(默认是2 KB)

  • -XX:TLABWasteTargetPercent = N 设置TLAB空间占Eden区的百分比(默认是1%)

  • -XX:TLABWasteIncrement=N 默认值为4) TLAB 缓慢分配时允许的 TLAB 浪费增量,TLAB每经历一次慢分配,refill_waste允许的最大浪费空间就会增加N。

什么是慢分配?什么是快分配?

在 TLAB 内存充足的时候分配对象就是快分配,否则在 TLAB 内存不足的时候分配对象就是慢分配慢分配可能会发生两种处理:

1.线程获取新的 TLAB。老的 TLAB 回归 Eden,之后线程获取新的 TLAB 分配对象。

2.对象在 TLAB 外分配,也就 Eden 区。

7.TLAB的生命周期

TLAB 是线程私有的,线程初始化的时候,会创建并初始化 TLAB。同时,在 GC 扫描对象发生之后,线程第一次尝试分配对象的时候,也会创建并初始化 TLAB。 TLAB 生命周期停止(TLAB 生命周期停止不代表内存被回收,只是代表这个 TLAB 不再被这个线程私有管理)在:

  • 当前 TLAB 不够分配,并且剩余空间小于最大浪费空间限制,那么这个 TLAB 会被退回 Eden,重新申请一个新的

  • 发生 GC 的时候,TLAB 被回收。

原文链接:https://www.cnblogs.com/frankcui/p/14332213.html

原文链接:https://blog.csdn.net/zgz15515397650/article/details/119383089

原文链接:https://www.jianshu.com/p/a7414c0ebb17

原文链接:https://zhuanlan.zhihu.com/p/349173451

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值