JVM栈上分配&TLAB分配&逃逸分析
对线程栈的优化
栈上分配为什么需要栈上分配什么是栈上分配栈上分配的优点:栈上分配的缺点:TLAB为什么需要TLAB?标量替换标量替换的含义标量 VS 聚合量逃逸分析如何开启java jvm service client模式参考资料
栈上分配
为什么需要栈上分配
在我们的应用程序中,其实有很多的对象的作用域都不会逃逸出方法外,也就是说该对象的生命周期会随着方法的调用开始而开始,方法的调用结束而结束,对于这种对象,是不是该考虑将对象不在分配在堆空间中呢?
我们通过JVM内存分配可以知道JAVA中的对象都是在堆上进行分配,当对象没有被引用的时候,需要依靠GC进行回收内存,如果对象数量较多的时候,会给GC带来较大压力,也间接影响了应用的性能。
什么是栈上分配
所以,栈上分配是JVM提出的一种调优方案,JVM通过逃逸分析确定该对象不会被外部访问,如果不会逃逸可以将该对象在栈上分配内存,每个方法或者说每个线程都有属于自己独立的栈帧,随着方法的调用结束,这样该对象所占用的内存空间就可以随栈帧出栈而销毁,就减轻了垃圾回收的压力。
对象逃逸分析:就是分析对象动态作用域,当一个对象在方法中被定义后,它可能被外部方法所引用,例如作为调用参数传递到其他地方中。
栈上分配的优点:
1.可以在方法调用结束后自行销毁对象,无需垃圾回收器的介入,有效减小JVM的GC压力
2.栈上分配速度很快,有效提高程序性能
栈上分配的缺点:
1.栈的空间是有限的,栈空间存放不了大对象,遇到大对象的创建则还是会存放在堆空间中
TLAB
TLAB,全称Thread Local Allocation Buffer,即:线程本地分配缓存。这是一块线程专用的内存分配区域。TLAB占用的是eden区的空间。在TLAB启用的情况下(默认开启),JVM会为每一个线程分配一块TLAB区域。
为什么需要TLAB?
这是为了加速对象的分配。由于对象一般分配在堆上,而堆是线程共用的,因此可能会有多个线程在堆上申请空间,而每一次的对象分配都必须线程同步,会使分配的效率下降。考虑到对象分配几乎是Java中最常用的操作,因此JVM使用了TLAB这样的线程专有区域来避免多线程冲突,提高对象分配的效率
局限性:TLAB空间一般不会太大(占用eden区),所以大对象无法进行TLAB分配,只能直接分配到堆上.
标量替换
标量替换的含义
通过逃逸分析确定该对象不会被外部访问,并且对象可以被进一步分解时,JVM不会创建该对象,而是将该对象成员变量分解若干个被这个方法使用的成员变量所代替,这些代替的成员变量在栈帧或寄存器上分配空间,这样就不会因为没有一大块连续空间导致对象内存不够分配。
开启标量替换参数(-XX:+EliminateAllocations),JDK7之后默认开启
标量 VS 聚合量
标量替换 ? 那什么是标量 ?
- 标量: 不可被进一步分解的量,而JAVA的基本数据类型就是标量(比如int,long等基本数据类型以及reference类型等) 。
- 聚合量: 标量的对立就是可以被进一步分解的量,称之为聚合量。 在JAVA中对象就是可以被进一步分解的聚合量。
逃逸分析
逃逸分析(Escape Analysis)是目前Java虚拟机中比较前沿的优化技术。这是一种可以有效减少Java 程序中同步负载和内存堆分配压力的跨函数全局数据流分析算法。通过逃逸分析,Java Hotspot编译器能够分析出一个新的对象的引用的使用范围从而决定是否要将这个对象分配到堆上。
逃逸分析的基本原理是:分析对象动态作用域,当一个对象在方法里面被定义后,它可能被外部方法所引用,例如作为调用参数传递到其他方法中,这种称为方法逃逸;甚至还有可能被外部线程访问到,譬如赋值给可以在其他线程中访问的实例变量,这种称为线程逃逸;从不逃逸、方法逃逸到线程逃逸,称为对象由低到高的不同逃逸程度。
如何开启
栈上分配的一个技术基础是进行逃逸分析。目的是判断对象的作用域是否有可能逃逸出逃逸体。
需要模式才有(64位版本是默认开启的)
java jvm service client模式
如果是64位的jdk 1.8 amd64,只能运行在Server模式下。而32位的jdk 1.8 i386,默认是运行在client模式下,可以通过修改jdk/jre/lib/i386/jvm.cfg文件里面的设置来指定默认的启动模式。
参考资料
Loading...