我想我应该做一个转义分析的小实验(Java 8,64位服务器JVM)。我想出了一个非常愚蠢的“应用程序”,我创建了大量的地址对象(它们由邮政编码、街道、国家和一个时间戳组成,这个对象是生成的)。此外,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对其进行了描述,在堆运行时堆中没有地址对象。整个应用程序在几秒钟内完成。
但是,当我像这样重构它时:
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对象的作用域更窄,它们不会转义方法,甚至是for循环块),那么为什么这两个版本的行为如此不同呢?
发布于 2015-10-19 14:27:27
您可以编写“如果时间戳可用7整除,则返回true”。这应该是显而易见的,发生了什么。在您的第一个代码中:
boolean valid = true;
for (int i=0;i<1_000_000_000;i++) {
valid = valid && doGenerate();
}
return valid;当时间戳碰巧不能被valid所除时,false就会变成7。然后,根据&&的工作方式,它将永远保持为false,并且由于&&短路,承载分配的方法doGenerate()将不再被调用。
相反,在你的第二个变体中
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;当时间戳不被valid所除时,false也将成为并保持为7,但唯一短路的是对isOk()的调用。不管valid的值如何,都会发生构造。
原则上,在这里可以消除Address的构造,但是这需要堆栈上的替换,因为它必须在循环运行时发生。目前还不清楚这是否是问题所在,但更重要的结论是,在这两种情况下,我们都不会看到EA发生,就像在第一种情况下,您根本没有调用包含分配的方法(在未知的调用之后,但期望调用的次数很少)。
因此,这两个例子是不等价的,不允许得出结论的逃逸分析。
https://stackoverflow.com/questions/33203018
复制相似问题