JVM:开启标量替换后仍有部分对象在堆中生成
Java JVM About 4,862 words标量替换
将普通对象中的字段拆解为基本数据类型和字符串,并且直接讲这些字段存放在线程栈中的局部变量表中,使得不用在堆中开辟空间初始化对象。避免了在堆中竞争锁去申请空间new
对象。
测试代码
public class OnStackTest {
public static void alloc() {
User u = new User();
u.id = 5;
u.name = "test";
}
public static void main(String[] args) throws InterruptedException {
System.out.println("start visual vm...");
long b = System.currentTimeMillis();
for (int i = 0; i < 100000000; i++) {
alloc();
}
System.out.println("loop end...");
long e = System.currentTimeMillis();
System.out.println(e - b);
LockSupport.park();
}
}
public class User {
public int id = 0;
public String name = "";
}
问题
在使用VisualVM
观察,虽然开启了EliminateAllocations
标量替换,禁用了TLAB
本地线程分配缓冲,但还是有部分对象在堆中生成了。
原因
EliminateAllocations
JVM
默认启用了分层编译器,标量替换EliminateAllocations
是只对于C2
编译器有效。
C1
编译器默认在收集1500
次方法调用后开启优化编译。
C2
编译器默认在收集10000
次方法调用后开启优化编译。
-XX:-TieredCompilation
关闭分层编译器,只有HotSpot Server
虚拟机支持次命令,故需要与-server
指令一起使用(对于默认是server
的虚拟机可以不加,使用java -version
可查看虚拟机是哪种模式)
-Xcomp
强制方法在第一次调用时就进行编译优化。
-XX:CompileThreshold
开启优化编译的阈值,尽可能的在这个阈值内完成优化编译,一般都会大于这个值。
如果设置的过小,比如设置为1
,则会发现C2
编译器没办法收集到优化信息导致不进行优化。
设置为0
,则表示不启用C2
编译器。
必须在关闭分层编译器的情况下生效,即设置-XX:-TieredCompilation
。
-XX:CompileThreshold 与 -Xcomp
-XX:CompileThreshold
与-Xcomp
指令一起使用,则可以精确控制在方法调用几次后开启优化编译。
如:-XX:CompileThreshold=1 -Xcomp
,表示方法调用一次后达到触发优化编译的条件,可以看见在堆上分配了2
次,强制第一次调用时生成了一个,再调用一次记录为阈值(个人认为-Xcomp
调用的这次不记录在CompileThreshold
中),使用VisualVM
可以见到有2
个Live Objects
。
-XX:+PrintCompilation
打印编译信息
-XX:CompileCommand="print,OnStackTest::alloc"
OnStackTest
的alloc
方法的编译信息,可以看到是使用C2
编译器。
分层编译器
默认为分层编译器。
Compiled method (c1) 318 203 3 OnStackTest::alloc (20 bytes)
total in heap [0x0000023e0c345190,0x0000023e0c345790] = 1536
relocation [0x0000023e0c345308,0x0000023e0c345358] = 80
main code [0x0000023e0c345360,0x0000023e0c3455e0] = 640
stub code [0x0000023e0c3455e0,0x0000023e0c345678] = 152
oops [0x0000023e0c345678,0x0000023e0c345680] = 8
metadata [0x0000023e0c345680,0x0000023e0c345698] = 24
scopes data [0x0000023e0c345698,0x0000023e0c3456e8] = 80
scopes pcs [0x0000023e0c3456e8,0x0000023e0c345788] = 160
dependencies [0x0000023e0c345788,0x0000023e0c345790] = 8
Could not load hsdis-amd64.dll; library not loadable; PrintAssembly is disabled
ImmutableOopMap{}pc offsets: 389 402
ImmutableOopMap{rax=Oop }pc offsets: 435 468 Compiled method (c2) 320 205 4 OnStackTest::alloc (20 bytes)
total in heap [0x0000023e13841510,0x0000023e13841728] = 536
relocation [0x0000023e13841688,0x0000023e13841690] = 8
main code [0x0000023e138416a0,0x0000023e138416c0] = 32
stub code [0x0000023e138416c0,0x0000023e138416d8] = 24
oops [0x0000023e138416d8,0x0000023e138416e0] = 8
metadata [0x0000023e138416e0,0x0000023e138416e8] = 8
scopes data [0x0000023e138416e8,0x0000023e138416f0] = 8
scopes pcs [0x0000023e138416f0,0x0000023e13841720] = 48
dependencies [0x0000023e13841720,0x0000023e13841728] = 8
C2 编译器
参数:-XX:-TieredCompilation -server
。
Compiled method (c2) 9609 3337 OnStackTest::alloc (20 bytes)
total in heap [0x00000299adf3ca10,0x00000299adf3cc58] = 584
relocation [0x00000299adf3cb88,0x00000299adf3cb90] = 8
main code [0x00000299adf3cba0,0x00000299adf3cbc0] = 32
stub code [0x00000299adf3cbc0,0x00000299adf3cbd8] = 24
oops [0x00000299adf3cbd8,0x00000299adf3cbe0] = 8
metadata [0x00000299adf3cbe0,0x00000299adf3cbe8] = 8
scopes data [0x00000299adf3cbe8,0x00000299adf3cc00] = 24
scopes pcs [0x00000299adf3cc00,0x00000299adf3cc50] = 80
dependencies [0x00000299adf3cc50,0x00000299adf3cc58] = 8
Could not load hsdis-amd64.dll; library not loadable; PrintAssembly is disabled
ImmutableOopMap{}pc offsets: 24 Compiled method (c2) 9664 3353 OnStackTest::alloc (20 bytes)
total in heap [0x00000299adf3ed90,0x00000299adf3efa8] = 536
relocation [0x00000299adf3ef08,0x00000299adf3ef10] = 8
main code [0x00000299adf3ef20,0x00000299adf3ef40] = 32
stub code [0x00000299adf3ef40,0x00000299adf3ef58] = 24
oops [0x00000299adf3ef58,0x00000299adf3ef60] = 8
metadata [0x00000299adf3ef60,0x00000299adf3ef68] = 8
scopes data [0x00000299adf3ef68,0x00000299adf3ef70] = 8
scopes pcs [0x00000299adf3ef70,0x00000299adf3efa0] = 48
dependencies [0x00000299adf3efa0,0x00000299adf3efa8] = 8
相关参数
-Xmx1g -Xms1g -XX:+DoEscapeAnalysis -XX:+PrintGCDetails -XX:-UseTLAB -XX:+EliminateAllocations -XX:+PrintCompilation -XX:CompileCommand="print,OnStackTest::alloc" -XX:-TieredCompilation -server -XX:CompileThreshold=1 -Xcomp
参考
https://stackoverflow.com/questions/64739969/why-jvm-xxeliminateallocations-fail
————        END        ————
Give me a Star, Thanks:)
https://github.com/fendoudebb/LiteNote扫描下方二维码关注公众号和小程序↓↓↓