1. 程式人生 > >java虛擬機器(第二版) 第二章總結 (三)-手工復現java虛擬機器記憶體溢位(OutOfMemoryError異常)

java虛擬機器(第二版) 第二章總結 (三)-手工復現java虛擬機器記憶體溢位(OutOfMemoryError異常)

 

文章概述

的java虛擬機器記憶體溢位的簡要概述,復現堆記憶體,棧記憶體,方法區的執行時常量池記憶體等區域的溢位情況,以及上述區域發生記憶體溢位的判斷方式和解決思路。

 

1,概述:
      IDE為eclipse,需要在執行中作為配置頁籤中配置虛擬機器引數。

GC:Roots到物件之間始終可達即可。

 

注:GC Roots,java垃圾回收執行緒判斷物件是否存活的方式,java採用的是可達性分析演算法,而不是傳說中的引用計數演算法。

 

可達性分析演算法的基本思路是當“GC Roots”的物件到其他物件是可達的,則該物件被認為是存活的,是不能被垃圾收集器回收的,反之則會被回收。

 

一個公式:作業系統記憶體= [Xmx]最大堆容量+ [MaxPermSize]最大方法區容量+程式計數器記憶體(很小,可以不計)+虛擬機器程序本身耗費的記憶體+ [-Xss]虛擬機器棧和本地方法棧記憶體*執行緒數+直接記憶體


java語言中被作為GC Roots的物件有:

 

虛擬機器棧(棧幀中的本地變量表)中引用的物件。
方法區中類靜態屬性
引用的物件。
本地方法棧中JNI(即一般說的Native方法)引用的物件。

 

所以書中給出的示例程式碼是始終不釋放某物件並同時迴圈一直追加知道記憶體不足。

 

2,堆記憶體溢位

 

虛擬機器引數:-Xms20m -Xmx20m-XX:+ HeapDumpOnOutOfMemoryError

結果如下:

可以看到Java堆空間的提示。

解決思路:

    通過記憶體分析工具分析轉儲的堆轉儲快照檔案,如果是記憶體洩漏,則應該定位不該存活的物件並解決。如果是記憶體溢位,則需要調整記憶體大小。

 

記憶體洩漏:指本不該存活的物件還存活著,為程式問題,應修改程式。

記憶體溢位:指雖然出現了OutOfMemoryError異常,但記憶體中的物件都是必須存在的,則此時應調整記憶體大小。

 

3,虛擬機器棧和本地方法棧溢位

虛擬機器引數:-Xss 128k

的StackOverflowError異常

解決思路:

    一個很難想到的解決方式是線上程數量不變的情況下減少最大堆和減少棧容量,不過還是需要根據具體情況按照文章開頭的公式進行分析即可

 

4,方法區和執行時常量池溢位(程式碼在JDK1.6中有效,原因和intern()方法的內部實現有關)

虛擬機器引數:-XX:PermSize = 10M-XX:MaxPermSize = 10M

結果:

解決思路:

    因為方法區主要用於存放類的相關資訊,如類名,訪問修飾符,常量池,欄位描述,方法描述等。

此區域在框架使用CGLIB。大量JSP檔案的應用,基於OSGI的應用(因為被不同類載入器載入的同一個類,也會被認為是不同的類)等動態生成類時有可能出現記憶體溢位。因此應重點考慮是否是由上述原因引起。

 

5,本機直接記憶體
DirectMemory容量可通過-XX:MaxDirectMemorySize指定,如果不指定,則預設與Java堆最大值(-Xmx指定)一樣。

 

解決思路:

    此區域記憶體溢位的明顯特徵是在堆轉檔案中不會看見明顯的異常,且OOM後轉儲檔案很小,而程式中又直接或間接使用了NIO,那就可以考慮檢查一下是不是此區域引起的問題。

歡迎大家關注我的公眾號號“up隨想”

本節完