一、TLAB介绍
TLAB(Thread Local Allocation Buffer)是在Hotspot1.6引入的新技术,目的是提升在堆上创建对象的性能。
如果一个对象被创建到堆上时,需要在堆上申请指定大小的内存供新创建的对象使用,在这个过程中,堆会通过加锁或指针碰撞的方式防止同一块被重复申请,在JVM中,内存分配是一个非常频繁的动作,而给堆加锁或者校验碰撞指针的方式必定会影响内存创建效率,TLAB的出现就是为了优化这个问题。
二、TLAB细节
TLAB是线程的一块私有内存,这块内存在堆中,可以通过JVM参数-XX:+UseTLAB开启。
-
在线程启动的时候会在堆中为其申请一块指定大小的内存,这块内存只给当前线程使用,属于线程私有的,如果线程需要为线程内的对象分配内存,就再自己的空间上分配,这样就不存在内存竞争的情况了,大大的提升了分配效率;
void initialize_tlab() { if (UseTLAB) { tlab().initialize(); } }
-
当TLAB空间容量不足时,就新申请一个TLAB,原来的那个TLAB区里的对象还维持现状,因为对象只能感知到自己在Eden区。
-
TLAB空间的内存非常小,默认大小仅有Eden区的1%,也可以通过JVM参数-XX:TLABWasteTargetPercent设置TLAB空间占Eden空间的百分比大小,一般用默认的就可以。
# 开启TLAB -XX:+UseTLAB # 关闭TLAB -XX:-UseTLAB # 设置每个TLAB区域占Eden区的大小比例 -XX:TLABWasteTargetPercent
三、TLAB规则
-
我们下载openjdk,到查看文件
hotspot/src/share/vm/memory/threadLocalAllocBuffer.hpp
,这是TLAB的源码实现,看一下类中的属性:从类中我们看到四个HeapWord实例,对于我们来说只需要关心start、top和end,我们结合和源码分析一下每个变量的用途。
-
根据它们的注释我们可以知道start是TLAB的地址,end是申请的TLAB空间的尾部,也就是通过start和end就可以标识出这个TLAB所管理的区域,防止其他线程再来分配这块空间。
-
top是归属线程最后一次申请空间的尾位置,当top撞上end的时候就表示这个TLAB的空间用完了,这时会申请一个新的TLAB。
-
-
每一个TLAB空间大小都是固定的,默认的是Eden区大小的的1%,既然大小是固定的,那么肯定会出现空间浪费的情况,比如TLAB大小是100kb,已经被使用了90kb,此时有一个12kb的对象来申请空间,但是TLAB的剩余空间已经不足以分配给这个对象了,此时怎么办?是新申请一个TLAB,还是直接分配到Eden区?在设计TLAB的时候就已经考虑到这种情况了,使用变量
refill_waste_limit
来控制一个TLAB允许被浪费的空间大小。-
如果
refill_waste_limit
的值是5kb的话,那么一个TLAB允许浪费的最大空间就是5kb,但是上述情况下TLAB还剩10kb的空间,不满足浪费条件,那么这个TLAB就不能被遗弃,还需要继续使用,所以不能申请新的TLAB,那么这个12kb的对象就只能被分配到Eden区; -
如果
refill_waste_limit
的值是10kb,那么上述情况已经满足了空间可浪费的大小限制,此时就会直接遗弃当前的TLAB,重新申请一个新的来存放申请对象; -
如果对象需要的空间特别大,超过了整个TLAB的大小,那么就会被直接放到Eden区。
-
-
TLAB是允许浪费一部分空间的,这会导致在大量TLAB都浪费了部分空间的时候Eden区空间不连续,影响整个Eden区的使用。
![image-20200501225512825](https://i-blog.csdnimg.cn/blog_migrate/fceb86080d6fee82a2a1d51ce15e310d.png)
四、总结
基本上TLAB介绍到这里就可以了,再深入一点的话就要到C++代码层面了。