Java虛擬機器棧是執行緒私有的,它的生命週期和執行緒同步
一個執行緒每執行到一個方法,JVM就會建立一個棧幀(用於儲存基本資料型別、物件指標和返回值等),並將棧幀壓入棧中。
程式碼示例:
public class Example {
public static void main(String[] args) {
Example example = new Example();
example.m1();
}
public void m1() {
int x = 0;
m2();
}
public void m2() {
Apple y = new Apple();
m3();
}
public void m3() {
float z = 1.0f;
}
}
執行流程:
- 首先,程式啟動,main() 方法入棧。
- 然後,m1() 方法入棧,宣告 int 型別變數 x = 0。注意,無論是 x 還是 0 都儲存在棧幀中。
- 接著,m2() 方法入棧,建立了一個 Apple 物件,並被賦給變數 y。請注意,實際的 Apple 物件是在 Java 堆記憶體中建立的,而不是執行緒棧中,只有 Apple 物件的引用以及變數 y 被包含在棧幀裡。
- 最後,m3() 方法入棧,宣告 float 型別變數 z = 1.0f。同理,z 和 1.0f 都被儲存在棧幀裡。
當方法執行完成後,所有的執行緒棧幀將按照後進先出的順序逐一出棧,直至棧空為止
Java執行緒棧預設大小是由作業系統決定的,一般為1MB或2MB。如果需要調整執行緒棧的大小,可以使用-Xss
引數來設定。在實際開發中,預設的執行緒棧大小通常已經足夠滿足需求,只有在遇到執行緒棧溢位錯誤時才需要考慮調整大小。
一旦遞迴過深,執行緒棧的容量增長超過了允許的棧容量,就會丟擲StackOverflowError(棧溢位) 錯誤。
那麼什麼是記憶體洩漏和記憶體溢位呢?
- 記憶體溢位(out of memory):指程式在申請記憶體時,沒有足夠的記憶體空間供其使用。
- 記憶體洩露(memory leak):指程式在申請記憶體後,無法釋放已申請的記憶體空間,進而導致記憶體逐漸被佔光。
- memory leak 最終會導致 out of memory。
記憶體溢位異常丟擲的原因(包括但不限於):
- 如果新執行緒在申請棧時失敗了,就會丟擲 OutOfMemoryError(記憶體溢位) 錯誤。
- 或者當JVM不能分配給物件的建立空間,也會丟擲 OutOfMemoryError 錯誤。
小結:
- StackOverflowError:遞迴過深,遞迴沒有出口。
- MemoryLeak:申請記憶體後,無法釋放已申請的記憶體空間。
- OutOfMemoryError:JVM空間溢位,建立物件速度高於GC回收速度。