2017-04-16 149 views
0

我有一個函數彈出堆棧時內存會發生什麼變化?

public void f() { 
    int x = 72; 
    return; 
} 

所以x存儲在可能的地址0x9FFF

當函數返回時,內存在那個地址會發生什麼?它還在嗎? I.e的值仍然是72?還是完全無效?

+5

爲什麼'C'標籤? ''return;'也是不必要的。 – pzaenger

+3

在C語言中,對於大多數體系結構而言,直到另一個代理覆蓋它(即ISR)時,該值仍然存在。在Java中,VM可以用許多不同的方式實現堆棧,並且JIT不必將VM堆棧轉換爲本地堆棧。所以,從Java的角度來看,它是失敗的。 –

+0

@MargaretBloom好的信息,實際上可以添加爲答案,這比我的回答更好:) – EJoshuaS

回答

0

我不是在不注意規格,但我猜這不是技術上的定義。

其實我試過類似的東西在C++中一次,它是,事實上,72(或不管我放在那裏的函數調用返回前)如果我沒有記錯,所以該機並沒有真正經歷寫0到那個位置或者什麼。

這也是一些實現細節。我也用MIPS彙編語言實現了它(如果我能挖掘它,我會包含一個代碼示例)。基本上,當我需要寄存器時,我只需通過我需要的很多局部變量來「增長」堆棧,將所需的寄存器中的當前值存儲爲任何值(以便稍後可以恢復它們),並重新使用寄存器。如果這是實現,則該值實際上可以包含調用者中的本地變量的值。不過,我不認爲這正是Java所做的。

TL; DR這是一個實現細節,但在C中,至少它不會覆蓋內存中的值,直到它真正需要它爲止。 Java很難預測。

2

Java編程語言和Java虛擬機都沒有定義彈出框架後堆棧幀的內存會發生什麼變化。這是一個低層次的實現細節,被更高層次的抽象所掩蓋。事實上,Java語言和JVM字節碼使設計不可能從堆棧中檢索已經刪除的值(與C/C++不同)。

但實際上,Java中的堆棧框架的行爲與C中的堆棧框架類似。增加堆棧會使指針碰撞(通常是向下)並分配空間來存儲變量。收縮堆棧通常會將指針向上移動,並簡單地將舊值保存在內存中而不會覆蓋它們。如果您對JVM的堆棧內存區域有低級訪問權限,這是您應該看到的行爲。

請注意,這是在Java中不可能做到像C一招,你嘗試讀取未初始化堆棧變量:

static boolean firstTime = true; 

public void f() { 
    int x; 
    if (firstTime) { 
     x = 72; 
     firstTime = false; 
    } else { 
     // Compile error: Variable 'x' may not have been initialized 
     System.out.println(x); 
    } 
} 

其他堆棧行爲在JVM實現是可能的。例如,當彈出框架時,可以將4 KiB虛擬內存頁面取消映射回操作系統,這將真正擦除舊值。同樣在諸如Mill這樣的機器體系結構中,堆棧內存被特殊對待,以便堆棧增長將始終返回一個填充了零字節的區域,從而節省了從內存中實際加載舊值的工作。

2

在C中是未定義的行爲

在實踐中,如果你嘗試類似:

int *ptr; 

void foo() { 
    bar(); 
    printf("%d", *ptr); 
} 

void bar() { 
    int x = 72; 
    ptr = &x; 
} 

然後,它的可能,在C的大多數實現,foo()將打印72。這是因爲雖然ptr引用的地址可用於重新分配,但它不可能被重新分配,並且沒有任何內容被覆蓋。程序繼續運行的時間越長,初始化更多的局部變量,並調用malloc(),這個內存地址將被重新使用的可能性就越大,並且值也會改變。

但是在C規範中沒有任何說明必須是這種情況 - 實現可能爲爲0,只要它超出範圍,或者在嘗試讀取時遇到運行時恐慌,或者,好吧,任何事 - 這就是「未定義」的意思。

作爲程序員,您應該小心避免這樣做。很多時候它會導致錯誤,但有些時候你會導致間歇性的錯誤,這是最難追查的。

在Java中,雖然內存在超出範圍後仍可能包含72,但實際上沒有辦法訪問它,所以它不會影響程序員。在Java中可以訪問的唯一方式是,如果有「官方」引用,那麼它不會被標記爲垃圾回收,並且不會超出範圍。

+1

總體回答良好。但是當你說「在Java中......如果有官方引用它時」,這是不可能的,因爲原始的int不是引用。 – Nayuki

1

基本類型中爪哇被放置在棧上(成frame局部變量數組)。每次調用方法時都會創建一個新框架:

public void foo() { 
    int x = 72; // 'x' will be stored in the array of local variables of the frame 
} 

框架在其方法調用完成時被銷燬。此時所有局部變量部分結果可能仍駐留在堆棧上,但它們被放棄並不再可用。

相關問題