Thread Local Allocation Buffer JVM中TLAB

1、为什么有TLAB( Local)
总结一句话:堆上存放的对象实例多线程不安全,并且影响分配速度 。如果能将对象实例分配在独立的一块区域,那就能解决多线程不安全和分配速度慢问题,这就是TLAB 。
2、什么是TLAB
3、TLAB使用
4、通过逃逸分析判断对象实例可能被优化成栈上分配
如何将堆上的对象分配到栈,需要使用逃逸分析手段 。
在《深入理解Java虚拟机》中关于Java堆内存有这样一段描述:
随着JIT编译期的发展与逃逸分析技术逐渐成熟,栈上分配、标量替换优化技术将会导致一些微妙的变化,所有的对象都分配到堆上也渐渐变得不那么“绝对”了 。
在Java虚拟机中,对象是在Java堆中分配内存的,这是一个普遍的常识 。但是,有一种特殊情况,那就是如果经过逃逸分析( )后发现,一个对象并没有逃逸出方法的话,那么就可能被优化成栈上分配(TLAB). 。这样就无需在堆上分配内存,也无须进行垃圾回收了 。这也是最常见的堆外存储技术 。
【Thread Local Allocation BufferJVM中TLAB】此外,基于深度定制的,其中创新的GCIH(GCheap)技术实现off-heap,将生命周期较长的Java对象从heap中移至heap外,并且GC不能管理GCIH内部的Java对象,以此达到降低GC的回收频率和提升GC的回收效率的目的 。
5、逃逸分析概述
这是一种可以有效减少Java程序中同步负载和内存堆分配压力的跨函数全局数据流分析算法 。
通过逃逸分析,Java 编译器能够分析出一个新的对象的引用的使用范围从而决定是否要将这个对象分配到堆上 。
逃逸分析的基本行为就是分析对象动态作用域:
发生逃逸和未发生逃逸实例
public class EscapeAnalysis {public EscapeAnalysis obj;/*** 方法返回EscapeAnalysis对象,发生逃逸* @return*/public EscapeAnalysis getInstance() {return obj == null ? new EscapeAnalysis() : obj;}/*** 为成员属性赋值,发生逃逸*/public void setObj() {this.obj = new EscapeAnalysis();}/*** 对象的作用于仅在当前方法中有效,没有发生逃逸*/public void useEscapeAnalysis() {EscapeAnalysis e = new EscapeAnalysis();}/*** 引用成员变量的值,发生逃逸*/public void useEscapeAnalysis2() {EscapeAnalysis e = getInstance();}}
没有发生逃逸的对象,则可以分配到栈上,随着方法执行的结束,栈空间就被移除(这种主动释放内存的方式相比堆内对象等待GC要更好) 。
6、逃逸分析设置
参数设置:
在JDK 6u23 版本之后,中默认就已经开启了逃逸分析
这个默认大前提是启用了-模式,当然JVM默认也是-模式
如果使用的是较早的版本,开发人员则可以通过:
怎么判断是否启用了逃逸分析呢?
如果结果是“-XX:-”则为未启用,如果是“-XX:+”则启用了
7、代码实例比对启用逃逸分析和非逃逸分析
下述代码在主函数中进行了1亿次alloc 。调用进行对象创建,User实例的创建作用域未出方法,如果启用逃逸分析,则会启用TLAB 。咱们看下启用和不启用逃逸分析,执行时间和堆内对象使用情况 。
/*** @author liuchao* @date 2023/2/24*/public class Test {public static void main(String[] args) {long start = System.currentTimeMillis();for (int i = 0; i < 10000000; i++) {alloc();}// 查看执行时间long end = System.currentTimeMillis();System.out.println("花费时间:" + (end - start));// 方便查看堆内存中对象个数,线程sleeptry {Thread.sleep(100000);} catch (InterruptedException e) {throw new RuntimeException(e);}}public static void alloc() {//未发生逃逸User user = new User();}}class User {private int age;private String userName;public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getUserName() {return userName;}public void setUserName(String userName) {this.userName = userName;}}