2 回答

TA貢獻(xiàn)2003條經(jīng)驗(yàn) 獲得超2個(gè)贊
代碼示例用于說(shuō)明引用文本的最后一句話,“請(qǐng)注意,僅當(dāng)引用在堆棧上而不是存儲(chǔ)在堆中時(shí)才允許進(jìn)行這種優(yōu)化”,您將其從解釋中扯下來(lái)有點(diǎn)奇怪文本:
例如,考慮Finalizer Guardian模式:
class Foo {
private final Object finalizerGuardian = new Object() {
protected void finalize() throws Throwable {
/* finalize outer Foo object */
}
}
}
super.finalize如果子類(lèi)覆蓋并且finalize未顯式調(diào)用super.finalize.
如果允許對(duì)存儲(chǔ)在堆上的引用進(jìn)行這些優(yōu)化,那么 Java 編譯器可以檢測(cè)到該finalizerGuardian字段從未被讀取,將其清空,立即收集對(duì)象,并盡早調(diào)用終結(jié)器。這與意圖背道而馳:程序員可能想在 Foo 實(shí)例變得無(wú)法訪問(wèn)時(shí)調(diào)用 Foo 終結(jié)器。因此,這種轉(zhuǎn)換是不合法的:只要外部類(lèi)對(duì)象可訪問(wèn),內(nèi)部類(lèi)對(duì)象就應(yīng)該是可訪問(wèn)的。
所以代碼示例說(shuō)明了一個(gè)限制。規(guī)范中提到的“優(yōu)化轉(zhuǎn)換”包括在逃逸分析證明對(duì)象是純本地的之后應(yīng)用的對(duì)象標(biāo)量化,換句話說(shuō),優(yōu)化下的代碼跨越對(duì)象的整個(gè)生命周期。
但它不需要這樣的本地對(duì)象。正如規(guī)范已經(jīng)提到的,優(yōu)化的代碼可以將對(duì)象的字段保留在 CPU 寄存器中,而無(wú)需重新讀取它們,因此,不再需要保留對(duì)象引用。同樣,仍然在范圍內(nèi)的引用變量可能未被使用。如果該引用是對(duì)某個(gè)對(duì)象的唯一引用,則將其從優(yōu)化代碼中刪除允許更早地進(jìn)行垃圾回收。
這兩種情況仍然允許Foo實(shí)例被更早地消除或收集。這反過(guò)來(lái)將允許較早地收集 . 引用的對(duì)象(不再是)finalizerGuardian。但這并不能抵消這種限制的意圖。規(guī)范將優(yōu)化限制為不允許內(nèi)部對(duì)象早于外部對(duì)象被收集,但將兩者收集在一起沒(méi)有問(wèn)題,包括早于天真的預(yù)期。
通常,任意大的對(duì)象圖可能會(huì)在單個(gè)垃圾收集周期中被收集,可能比天真預(yù)期的要早,甚至完全被優(yōu)化掉。

TA貢獻(xiàn)2039條經(jīng)驗(yàn) 獲得超8個(gè)贊
這種優(yōu)化(逃逸分析)的一個(gè)經(jīng)典例子是一個(gè)帶有Point類(lèi)的計(jì)算:
class Point {
double x;
double y;
public Point(final double x, final double y) {
this.x = x;
this.y = y;
}
double length() {
return Math.sqrt(x * x + y * y);
}
static double calc() {
double result = 0;
for (int i = 0; i < 100; i++) {
// this allocation will be optimized
Point point = new Point(i, i);
result += point.length();
}
return result;
}
}
內(nèi)聯(lián)后就new不需要了,因?yàn)槲覀兛梢詫⑺凶侄翁崛〉骄植孔兞恐校?/p>
Point point = new Point(i, i);
double x = point.x;
double y = point.y;
result += Math.sqrt(x * x + y * y);
->
Point point = new Point(i, i);
double x = i;
double y = i;
result += Math.sqrt(x * x + y * y);
現(xiàn)在很明顯這new Point(i, i)是沒(méi)用的,JIT 只是刪除了這一行。
請(qǐng)注意,分配是在堆棧上,即在局部變量中。如果它在一個(gè)字段中,我們將無(wú)法進(jìn)行優(yōu)化,因?yàn)樗鎯?chǔ)在堆中。它是如何工作的。
關(guān)于您的代碼被剪斷:finalizerGuardian將始終在字段中(存儲(chǔ)在堆中),而 JVM 對(duì)此分配無(wú)能為力。此外,如果Point上面示例中的類(lèi)包含此類(lèi)字段,我認(rèn)為轉(zhuǎn)義分析無(wú)法刪除分配,因?yàn)樗赡軙?huì)改變?cè)夹袨椤?/p>
添加回答
舉報(bào)