天天看點

Java什麼情況下會報OutOfMemoryError

1. 若果線程請求的棧深度大于虛拟機所允許的深度,将抛出StatckOverflowError異常;若果虛拟機棧可以動态擴充(目前大部分的Java虛拟機都可動态擴充,隻不過Java虛拟機規範中也允許固定長度的虛拟機棧),當擴充時無法申請到足夠的記憶體時會抛出OutOfMemoryError異常。

2. 根據Java虛拟機規範的規定,Java堆可以處于實體上不連續的記憶體空間中,隻要邏輯上是連續的即可,就像我們的磁盤空間一樣,在實作時,既可以實作成固定大小的,也可以是可擴充的,不過目前主流的虛拟機都是按照可擴充來實作的(通過-Xmx和-Xms控制)。如果在堆中沒有記憶體完成執行個體配置設定,并且堆也無法再擴充時,将會抛出OutOfMemoryError異常。

3. 根據Java虛拟機規範的規定,當方法區無法滿足記憶體配置設定需求時,将抛出OutOfMemoryError異常。

4.  運作時常量池是方法區的一部分,自然會受到方法區記憶體的限制,當常量池無法在申請到記憶體時會抛出OutOfMemoryError異常。

5. 直接記憶體(Direct Memory)并不是虛拟機運作時資料區的一部分,也不是Java虛拟機規範中定義的記憶體區域,但是這部分記憶體也被頻繁地使用,而且也可能導緻OutOfMemoryError異常的出現。在JDK1.4中新加入了NIO(New Input/Output)類,引入了一種基于通道(Channel)與緩沖區(Buffer)的I/O方式,它可以使用Native函數庫直接配置設定堆外記憶體,然後通過一個存儲在Java堆裡面的DirectByteBuffer對象作為這塊記憶體的引用進行操作,這樣能在一些場景中顯著提高性能,因為避免了在Java堆和Native中來回複制資料。顯然,本機直接記憶體的配置設定不會受到Java堆大小的限制,但是,既然是記憶體,則肯定還是會受到本機總記憶體(包括RAM及SWAP區或分頁檔案)的大小及處理器尋址空間的限制。