深入理解JVM之記憶體地區與記憶體溢出
文章目錄
1.2. HotSpot虛擬機器
1.3. OOM異常的解決思路
1.4. 參考
Java記憶體地區與記憶體溢出異常
運行時資料區域
程式計數器
-
當前線程所執行的位元組碼的行號指標
-
當前線程私人
-
不會出現OutOfMemoryError情況
java虛擬機器棧
-
線程私人,生命週期與線程相同
-
java方法執行的記憶體模型,每個方法執行的同時都會建立一個棧幀,儲存局部變數表(基本類型、對象引用)、運算元棧、動態連結、方法出口等資訊
-
StackOverflowError異常:當線程請求的棧深度大於虛擬機器所允許的深度
-
OutOfMemoryError異常:如果棧的擴充時無法申請到足夠的記憶體
本地方法棧
與虛擬機器棧相似,主要為虛擬機器使用到的Native方法服務,在HotSpot虛擬機器中直接把本地方法棧與虛擬機器棧變形平板
Java堆(Java Heap)
java堆是被所有線程共用的一塊記憶體地區,在 虛擬機器啟動時建立。此地區的唯一目的就是儲存物件執行個體。java堆是垃圾收集器管理的主要區域。java堆還可以細分為:新生代與老年代。在細一點有 Eden空間、Form Survivor空間、To Survivor空間等。
方法區
運行時常量池
直接記憶體
-
NIO可以使用Native函數庫直接分配堆外記憶體,堆中的DirectByteBuffer對象作為這塊記憶體的引用進行操作
-
大小不受Java堆大小的限制,受本機(伺服器)記憶體限制
-
OutOfMemoryError異常:系統記憶體不足時
HotSpot虛擬機器
對象的建立
虛擬機器遇到一條new指令時,首先將去檢查這個對象的參數是否在常量池中定位到一個類的符號引用,並且檢查這個符號引用代表的類是否已被載入、解析和初始化過。如果沒有,必須先執行類的載入過程。
在類載入檢查通過後,虛擬機器將為新生對象分配記憶體。對象所需記憶體大小再類載入完成後便可確定。記憶體配置可以採用“指標碰撞”與“空閑列表”的方式。
對象的訪問定位
java程式需要通過棧上的reference資料來操作堆上的具體對象。訪問方式有使用控制代碼和直接指標兩種。
OOM異常的解決思路
產生Dump快照檔案:
-
通過jvm參數—XX:-HeapDumpOnOutOfMemoryError可以讓JVM在出現記憶體溢出是Dump出當前的記憶體轉儲快照
-
用jmap生產dump檔案,win通過工作管理員查看tomcat的進程pid,linux用ps命令查看進程pid,然後用jmap命令
先通過記憶體映像分析工具(如Eclipse的Memory Analyzer)進行分析,常見的情況有:
OOM異常樣本:
package oom;
- import java.util.ArrayList;
- import java.util.List;
-
- /**
- * VM Args: -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError
- * @ClassName: HeapOOM
- *
- */
- public class HeapOOM {
- static class OOMObject{
-
- }
-
- public static void main(String[] args) {
- List<OOMObject> list = new ArrayList<OOMObject>();
- while(true){
- list.add(new OOMObject());
- }
- }
- }