JVM逃逸分析之栈上内存分配
说明
1.例子在jdk1.8下示例栈上分配内存的例子;
2.切记一定要run,不能在debug模式下运行!!!
使用代码
package org.example;
public class StackAllocationTest {
public static void main(String[] args) throws InterruptedException {
long time = System.currentTimeMillis();
for (int i = 0; i < 10000000; i++) {
test();
}
System.out.println(String.format("time = %dms", System.currentTimeMillis() - time));
Thread.sleep(10000000);
}
private static void test() {
// a对象方法内不逃逸,希望能在栈上进行分配空间
A a = new A();
}
static class A {
}
}
试验1 jstat -gc分析
不启用逃逸分析
jvm参数如下:
-Xmx10m -Xms10m -XX:-DoEscapeAnalysis -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError`
启动程序,然后使用jstat进行分析
D:\YDIdeaWorkspace\java-test>jps
3364 StackAllocationTest
D:\YDIdeaWorkspace\java-test>jstat -gc 3364
S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
512.0 512.0 192.0 0.0 2048.0 753.1 7168.0 740.2 4864.0 3837.2 512.0 428.9 **88** 0.030 0 0.000 0.030
启用逃逸分析
-XX:-DoEscapeAnalysis改为-XX:+DoEscapeAnalysis,结果如下
D:\YDIdeaWorkspace\java-test>jstat -gc 4400
S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
512.0 512.0 0.0 504.0 2048.0 1089.4 7168.0 296.0 4864.0 3638.7 512.0 400.4 3 0.002 0 0.000 0.002
结果表示启用逃逸分析后,gc的次数从88下降到了3,说明大部分对象并没有在堆上创建
试验2 jmap -histo分析
调高堆容量
-Xmx3G -Xms3G -XX:-DoEscapeAnalysis -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError`
使用jmap分析
D:\YDIdeaWorkspace\java-test>jps
10320 StackAllocationTest
D:\YDIdeaWorkspace\java-test>jmap -histo 10320
num #instances #bytes class name
----------------------------------------------
1: 10000000 160000000 org.example.StackAllocationTest$A
....
同理-XX:-DoEscapeAnalysis改为-XX:+DoEscapeAnalysis后:
D:\YDIdeaWorkspace\java-test>jmap -histo 4976
num #instances #bytes class name
----------------------------------------------
1: 770 58405912 [I
2: 1312 2508296 [B
3: 118001 1888016 org.example.StackAllocationTest$A
....
可以看到不开启逃逸分析时,堆上A的实例有1000w个;开启后,堆上只有12w不到。侧面反映开启后对象并不在堆上分配空间了!
试验3 默认参数
-Xmx3G
-Xms3G
D:\YDIdeaWorkspace\java-test>jmap -histo 7092
num #instances #bytes class name
----------------------------------------------
1: 770 58150768 [I
2: 1312 2508144 [B
3: 134017 2144272 org.example.StackAllocationTest$A
可以看到jdk1.8是默认开启的
加入-XX:+PrintFlagsFinal
[Global flags]
bool DoEscapeAnalysis = true {C2 product}
bool EliminateAllocations = true {C2 product}
bool EliminateLocks = true {C2 product}
可以看到逃逸分析默认开启,并且标量替换、同步锁消除 也是默认开启的(这2个需要逃逸分析开启)