线程本地分配缓存TLAB

概念

为了避免一系列的非线程安全问题,同时还能提升内存分配的吞吐量,它是在eden空间进行分配的,每个线程都有一个缓冲区域,空间只有Eden的1%,可以通过-XX:UseTLAB来配置是否开启tlab(默认是开启的),通过-XX:TLABWasteTargetPercent来设置TLAB空间所占用Eden空间的百分比大小。

为什么需要tlab

在jvm中堆区是共享的区域,一旦在并发环境下从堆中划分内存空间,就可能会遇到分配到同一个内存地址的问题,为了避免多个线程操作同一个地址,就需要使用加锁等机制,但这会影响分配速度,因此使用tlab可以避免在多线程分配内存时的非线程安全问题,同时还能提升内存分配的吞吐量。

尽管不是所有的对象实例都能在tlab中成功分配,但jvm确实是将tlab作为内存分配的首选项,一旦分配失败,jvm就会尝试着通过使用加锁机制确保数据操作的原子性,从而直接在Eden空间中分配内存。
eden空间中tlab占的位置示例图:
在这里插入图片描述

tlab对象的分配过程:
在这里插入图片描述

优先分配到tlab空间中,如果成功则继续对象的初始化,如果失败,则由eden分配到非tlab区域。

代码实例:
通过配置tlab开启与否,来验证开启tlab是否会影响对象分配的效率。

package com.lydon.test;
import java.util.ArrayList;


public class TlabTest {
    
    
    public static void main(String[] args) {
    
    
        long startTime = System.currentTimeMillis();
        for (int i = 0; i<100000000;i++){
    
    
            ArrayList<String> list = new ArrayList();
            list.add(""+i);
        }


        long endTime = System.currentTimeMillis();
        System.out.println(endTime - startTime);
    }
}

当jvm参数为:-XX:+UseTLAB -XX:-DoEscapeAnalysis -server时
在这里插入图片描述

当jvm参数为:-XX:-UseTLAB -XX:-DoEscapeAnalysis -server时
在这里插入图片描述

可以看到耗时差异有将近3秒之多。

常见问题与答案

1、tlab跟java程序的多线程控制什么关系,java程序在多线程环境下不控制线程安全也可以最终线程安全吗?
答:跟java代码中的多线程安全无关系,这里只是指多线程下在堆空间中对对象的内存分配安全问题。

2、为什么多线程环境下分配内存会出现线程安全问题?
Java 程序会极其频繁的创建对象并为对象分配内存空间,一般情况下对象是分配在堆上的,堆又是全局共享的,所以会存在多个线程同时在堆上申请空间,而堆要同步处理,导致性能下降,而且同时为多个线程分配内存又可能会存在多个线程抢占一个内存地址的问题。
那么为了解决这一问题,Java 虚拟机提供了 TLAB 分配。TLAB 全称是 Thread Local Allocation Buffer,线程本地分配缓存,是一个线程私有的内存分配区域。虚拟机在 eden 区为每一个线程分配一块线程专用的内存区域 TLAB 区域。这样多个线程同时在堆上申请空间时,可以直接在当前线程自己的 TLAB 区域分配对象,不必等待堆同步处理,提高了效率。

3、什么时候tlab分配成功,什么时候分配失败?
由于tlab总空间只有eden空间大小的1%,因此当需要分配的对象内存大小太大,不足以放进tlab时,就会出现分配失败的情况下,就会由分配到非tlab的eden空间中,如果eden空间也不够大(此时幸存者区一般也不够),就会直接到老年代区去。

猜你喜欢

转载自blog.csdn.net/lyd135364/article/details/121064812