我想我会做一个逃逸分析的小实验(Java 8、64 位服务器 JVM)。我想出了这个非常愚蠢的“应用程序”,我在其中创建了很多 Address 对象(它们由邮政编码、街道、国家和生成对象的时间戳组成。此外,Address 有一个 isOk() 方法,它返回如果时间戳可以被 7 整除,则为 true...)。
所以这是程序:
private boolean generate() {
boolean valid = true;
for (int i=0;i<1_000_000_000;i++) {
valid = valid && doGenerate();
}
return valid;
}
private boolean doGenerate() {
long timeGenerated = System.currentTimeMillis();
Address address = new Address(1021, "A Street", "A country", timeGenerated);
return address.isOk();
}
到目前为止一切顺利,我使用 jVisualVM 对其进行了分析,在它运行时堆上没有 Address 对象。整个应用程序在几秒钟内完成。
但是,当我像这样重构它时:
private boolean generate() {
boolean valid = true;
for (int i=0;i<1_000_000_000;i++) {
long timeGenerated = System.currentTimeMillis();
Address address = new Address(1021, "A Street", "A country", timeGenerated);
valid = valid && address.isOk();
}
return valid;
}
Baaang,没有逃逸分析,每个 Address 对象最终都分配在堆上,垃圾回收周期很长。为什么会这样?我的意思是,Address 实例不会以任何一种方式转义(在第二个版本中,Address 对象的范围更窄,它们不会转义方法,甚至不会转义 for 循环块),那么为什么两个版本的行为如此不同呢?