第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

JVM 何時將成員變量引用存儲在堆棧上?

JVM 何時將成員變量引用存儲在堆棧上?

猛跑小豬 2022-06-04 10:39:19
我正在閱讀Java SE 規(guī)范的第 12.6.1 節(jié),它說:可以設(shè)計優(yōu)化程序的轉(zhuǎn)換,將可到達的對象的數(shù)量減少到比那些天真地認為是可到達的要少。例如,Java 編譯器或代碼生成器可能會選擇將不再使用的變量或參數(shù)設(shè)置為 null,以使此類對象的存儲空間可能更快地被回收。如果對象字段中的值存儲在寄存器中,則會出現(xiàn)另一個示例。然后程序可能會訪問寄存器而不是對象,并且永遠不會再次訪問對象。這意味著該對象是垃圾。請注意,僅當(dāng)引用在堆棧上而不是存儲在堆中時才允許進行這種優(yōu)化。相關(guān)代碼為:class Foo {    private final Object finalizerGuardian = new Object() {        protected void finalize() throws Throwable {            /* finalize outer Foo object */        }    }} 我的問題是哪種 JVM 會將 finalizerGuardian 存儲在堆棧而不是堆中,為什么?
查看完整描述

2 回答

?
湖上湖

TA貢獻2003條經(jīng)驗 獲得超2個贊

代碼示例用于說明引用文本的最后一句話,“請注意,僅當(dāng)引用在堆棧上而不是存儲在堆中時才允許進行這種優(yōu)化”,您將其從解釋中扯下來有點奇怪文本:


例如,考慮Finalizer Guardian模式:


 class Foo {

     private final Object finalizerGuardian = new Object() {

         protected void finalize() throws Throwable {

             /* finalize outer Foo object */

         }

     }

 } 

super.finalize如果子類覆蓋并且finalize未顯式調(diào)用super.finalize.


如果允許對存儲在堆上的引用進行這些優(yōu)化,那么 Java 編譯器可以檢測到該finalizerGuardian字段從未被讀取,將其清空,立即收集對象,并盡早調(diào)用終結(jié)器。這與意圖背道而馳:程序員可能想在 Foo 實例變得無法訪問時調(diào)用 Foo 終結(jié)器。因此,這種轉(zhuǎn)換是不合法的:只要外部類對象可訪問,內(nèi)部類對象就應(yīng)該是可訪問的。


所以代碼示例說明了一個限制。規(guī)范中提到的“優(yōu)化轉(zhuǎn)換”包括在逃逸分析證明對象是純本地的之后應(yīng)用的對象標(biāo)量化,換句話說,優(yōu)化下的代碼跨越對象的整個生命周期。


但它不需要這樣的本地對象。正如規(guī)范已經(jīng)提到的,優(yōu)化的代碼可以將對象的字段保留在 CPU 寄存器中,而無需重新讀取它們,因此,不再需要保留對象引用。同樣,仍然在范圍內(nèi)的引用變量可能未被使用。如果該引用是對某個對象的唯一引用,則將其從優(yōu)化代碼中刪除允許更早地進行垃圾回收。


這兩種情況仍然允許Foo實例被更早地消除或收集。這反過來將允許較早地收集 . 引用的對象(不再是)finalizerGuardian。但這并不能抵消這種限制的意圖。規(guī)范將優(yōu)化限制為不允許內(nèi)部對象早于外部對象被收集,但將兩者收集在一起沒有問題,包括早于天真的預(yù)期。


通常,任意大的對象圖可能會在單個垃圾收集周期中被收集,可能比天真預(yù)期的要早,甚至完全被優(yōu)化掉。


查看完整回答
反對 回復(fù) 2022-06-04
?
largeQ

TA貢獻2039條經(jīng)驗 獲得超8個贊

這種優(yōu)化(逃逸分析)的一個經(jīng)典例子是一個帶有Point類的計算:



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不需要了,因為我們可以將所有字段提取到局部變量中,例如


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)是沒用的,JIT 只是刪除了這一行。


請注意,分配是在堆棧上,即在局部變量中。如果它在一個字段中,我們將無法進行優(yōu)化,因為它存儲在堆中。它是如何工作的。


關(guān)于您的代碼被剪斷:finalizerGuardian將始終在字段中(存儲在堆中),而 JVM 對此分配無能為力。此外,如果Point上面示例中的類包含此類字段,我認為轉(zhuǎn)義分析無法刪除分配,因為它可能會改變原始行為。


查看完整回答
反對 回復(fù) 2022-06-04
  • 2 回答
  • 0 關(guān)注
  • 114 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯(lián)系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動學(xué)習(xí)伙伴

公眾號

掃描二維碼
關(guān)注慕課網(wǎng)微信公眾號