1. 程式人生 > >定位JVM記憶體溢位問題思路總結

定位JVM記憶體溢位問題思路總結

JVM的記憶體溢位問題,是個常見而有時候有非常難以定位的問題。定位記憶體溢位問題常見方法有很多,但是其實很多情況下可供你選擇的有效手段非常有限。很多方法在一些實際場景下沒有實用價值。這裡總結下我的一些定位思路。

要定位JVM記憶體溢位問題,首先要對JVM的記憶體佈局有一定的瞭解,對常見的JVM記憶體工具要比較熟悉。所謂工欲善其事,必先利其器。而熟悉JVM的記憶體管理機制是你定位JVM記憶體問題的基石。首先介紹下JVM的記憶體管理機制:

JAVA程式和C類程式一個重要的區別就是JAVA中的記憶體回收管理工作有JVM完成,而不需要為程式中的每個new/malloc去delete/free。那JVM這麼智慧怎麼還有記憶體溢位問題呢,一個常見的原因是我們的JAVA程式中長時間的持有了不該持有的物件,或者申請了過多的物件使得JVM的記憶體不夠用。

JVM管理的幾個記憶體區域包括以下幾個記憶體區域:

1、  方法區:用於儲存JAVA類資訊、常量、靜態變數。這個區域也可以發生垃圾回收,比如當一些類不在被引用時JVM可以解除安裝這個類,不過這種回收動作很少發生。另外所有執行緒都共享方法區,因此執行緒對方法區的訪問被設計為執行緒安全的。

2、  虛擬機器棧:JAVA虛擬機器棧是執行緒私有的,每當啟動一個新執行緒時,JVM都會為它分配一個JAVA虛擬機器棧。沒當執行緒呼叫方法時,JVM都會為虛擬機器棧壓入一個棧幀,該棧幀用於儲存引數、區域性變數、中間運算結果、方法出口等。

3、  本地方法棧:和虛擬機器棧類似,只是他是專為JAVA中的Native方法服務。當執行緒進入本地方法後,它已經脫離的JVM的限制,甚至可以直接使用本地處理器中的暫存器。實際上本地方法的呼叫機制非常依賴於JVM的具體實現。

4、  堆:由JVM啟動時建立,由所有執行緒共享,用於存放物件的例項。一般情況下它是JVM中管理的記憶體中最大的一塊。絕大部分JVM記憶體問題都發生在這一塊。

5、  程式計數器:同虛擬機器棧一樣,它也是執行緒私有,啟動執行緒是建立。程式計數器的中儲存的內容總是下一條將被執行的指令的地址。

這幾個記憶體區域,除了程式計數器區域外,其他幾個區域都有可能發生記憶體溢位問題。常見的記憶體溢位有兩種:

1、方法區溢位。出現該問題時,JVM會報如下類似錯誤:java.lang.OutOfMemoryError : PermGenSpace ,Perm區的最大記憶體大小可以通過-XX:MaxPermSize=指定。引起這類記憶體溢位原因一般有兩個,一個是常量池太大,一個是需要載入的CLASS類太多。出現問題的時候排查下這兩種可能性,問題可以很快找到。這類問題程式穩定後也很少出現。

2、堆記憶體溢位。在JVM可使用的最大堆記憶體可以在啟動的時候通過-Xmx引數指定。堆記憶體溢位是最為常見的記憶體溢位問題,發生堆記憶體溢位時,JVM會報告如下錯誤:java.lang.OutOfMemoryError : java heap space。

這裡列舉下在定位堆記憶體溢位時,常見的方法和思路。堆記憶體溢位顧名思義就是,堆記憶體不夠用了,如果程式設計的最大對記憶體已經耗盡,那說明程式設計存在問題,不該申請很多記憶體的邏輯申請了很多的記憶體,該釋放的物件沒有釋放。最重要的問題是就要要找出到底是什麼物件沒有及時釋放,導致佔用了過多的記憶體。常見的方法:

a、  一個強大的定位工具是使用 jprofiler,通過jprofiler可以實時的監控到,當前的堆記憶體的總體使用情況及當前存活的物件、大小、分配樹、物件引用鏈等等,功能非常全面。如下圖所示:


通過該工具還可以實時的生成堆記憶體快照,然後通過不同時間點生成的記憶體快照做比較已確定記憶體增長點。但是實際使用中如果程式征程執行中佔用的記憶體就比較高,比如800M左右,而在32位機器上,JVM可以使用的最高記憶體在1280M左右,如果應用程式設定的最大堆記憶體是1024M,那麼實際即將發生堆記憶體溢位時,程式使用的記憶體是處一個比較高的位置。這時候通過jprofiler監控效果就很不理想,我在windows server 2003 32位伺服器上做測試,想通過jprofiler監控一個TOMCAT應用程式,該應用程式常態中佔用記憶體在800M左右,啟用jprofiler監控後,jprofiler監控程式本身就會變得很不穩定,常常莫名掛死(通過jprofiler監控應用程式的時候實際上上jprofiler對應用程式又做了一層包裝後啟動的,因此jprofiler監控程式掛死,等於被監控的程式掛死)。很難抓取到有用的資訊。

因此jprofiler在32位機器上只適用用小記憶體應用程式。

b、  使用JVM自帶的jmap工具匯出堆資訊分析,這個工具可以通過如下命令到處自定的JVM程序的堆記憶體:jmap –dump:format=b,file=heap.bin <pid>  。
但這個工具也有一樣的問題,在應用程式使用的記憶體處於高位時,使用jmap匯出堆資訊會出現空間不足,無法匯出的問題。Java自帶的很多工具都有類似的限制,所以實際上你的選擇並不多。

c、  在啟動JVM的時候加上以下兩個引數:

 -XX:HeapDumpPath=./dumpfile.hprof

-XX:+HeapDumpOnOutOfMemoryError

表示出現OOM錯誤後,將堆資訊dump出來。不過這個引數也有個問題,在實際使用的時候發現在windows平臺上,如果程式是以TOMCAT服務的方式執行,出現OOM錯誤後堆資訊也dump不出來。

d、  通過visualVM程式監控JVM,JDK 1.6中自帶的視覺化監控工具,這個工具比較實用,功能也比較強大。可以監控執行緒資訊,堆記憶體資訊,還可以實時匯出堆資訊以及強制GC。監控本地JVM直接啟動該工具後就可以監控,遠端監控需要啟動jstatd和jrxml。

啟動jstatd方法:新建jstatd.all.policy檔案,新增如下內容,tools.jar包的路徑根據實際情況修改:

grant codebase "file:/home/ndmc/tomcat/jdk/jre/lib/tools.jar" {

   permission java.security.AllPermission;

};

執行啟動命令./jstatd -J-Djava.security.policy=jstatd.all.policy,預設埠為1099,後面可跟-p指定其他埠號

使用jrxml遠端監控JVM的時候需要加上以下引數:

-Dcom.sun.management.jmxremote

-Dcom.sun.management.jmxremote.port=8849

-Dcom.sun.management.jmxremote.ssl=false

-Dcom.sun.management.jmxremote.authenticate=false

-Djava.rmi.server.hostname=hostip

監控效果如下:

在監控過程中可以手動的GC和DUMP堆記憶體,還可以設定Heap dump on OOME: enabled,使得在堆記憶體溢位的時候可以dump heap。不過根據實際使用,建議最高在堆記憶體即將溢位的時候就應該手動dump heap,因為等到OOM的時候常常程式已經掛死,heap已經導不出來了。

e、  匯出dump資訊後就可以通過jprofiler工具或者HeapAnalyzer做分析。這兩個工具都很強大,網上有很多的使用指導。可以初步分析出到底是什麼物件在佔用記憶體,以及相應的引用鏈,到這一步在結合原始碼在定位記憶體溢位問題就相對容易了。  

總結:定位記憶體溢位問題需要一個冷靜的頭腦、敏銳的觀察能力、縝密的分析問題能力。甚至常常需要根據一些現象做猜測然後驗證,找出最後的元凶,有可能記憶體的溢位是有多個方面引起的:程式碼BUG、軟體設計問題、網路的吞吐量以及網路連線問題、資料庫問題等都可能是相關需要排查的因素,甚至有時候可能是作業系統或者JVM本身存在的BUG導致。而能夠在JVM堆記憶體即將溢位的時候匯出堆資訊是問題定位的關鍵,只要能夠匯出堆資訊,一系列的猜測、分析是否正確就有可靠的證據。

相關推薦

定位JVM記憶體溢位問題思路總結

JVM的記憶體溢位問題,是個常見而有時候有非常難以定位的問題。定位記憶體溢位問題常見方法有很多,但是其實很多情況下可供你選擇的有效手段非常有限。很多方法在一些實際場景下沒有實用價值。這裡總結下我的一些定位思路。 要定位JVM記憶體溢位問題,首先要對JVM的記憶體佈局有一定

請問JVM引數_定位檢查記憶體溢位問題

-XX:+HeapDumpOnOutOfMemoryError 1、配置方法 在JAVA_OPTIONS變數中增加 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${目錄}。

jvm記憶體溢位問題的定位方法

jvm記憶體溢位問題的定位方法 今天給大家帶來JVM體驗之記憶體溢位問題的定位方法。 廢話不多說直接開始: 一、Java堆溢位 測試程式碼如下: import java.util.*; public class A { public static void main(String[] args) {

MAT使用-jvm記憶體溢位問題分析定位

1.MAT簡介: MAT 全稱 Eclipse Memory Analysis Tools 是一個分析 Java堆資

JVM——記憶體溢位記憶體洩漏的區別

今日本帥博主在研究JVM,今天我們就來遊走於記憶體溢位與記憶體洩漏之間,且看看它們是個啥,且又有啥子區別。 1.記憶體溢位和記憶體洩漏是啥 記憶體溢位 out of memory,是指程式在申請記憶體時,沒有足夠的記憶體空間供其使用,出現out of memory;比如申請了一個int

生產環境jvm記憶體溢位問題處理OutOfMemoryError

生產環境jvm記憶體溢位問題處理OutOfMemoryError 問題描述 服務正常部署執行後,前端介面偶爾出現請求無響應情況,頁面出現持續性卡頓。伺服器日誌報下面這個異常: Exception: java.lang.OutOfMemoryError thrown

jvm 記憶體溢位的多種原因及優化方法

讓我們看一下我們日常在開發過程中接觸記憶體溢位的異常:   Exception in thread "main" [Full GCjava.lang.OutOfMemoryError: Java heap space at java.util.Ar

Spark任務提交 yarn-cluster模式 解決jvm記憶體溢位問題 以及簡單概述jdk7方法區和jdk8元空間

yarn-cluster 提價任務流程 1、提交方式 ./spark-submit --master yarn --deploy-mode cluster --class org.apache.spark.examples.SparkPi ../lib/spark-exampl

JVM記憶體洩漏分析總結

1,登入linux伺服器 2,觀察JVM記憶體情況 > jps > jstat -class xxxxx 3,FGC檢視 jstat -gcutil pid js

死磕JVM-如何構造JVM記憶體溢位和棧溢位

為什麼要寫這個題目?我記得我在面試阿里的時候面試官問了我這個問題,當時沒能答得很好,只說了些概念的東西,很是心虛,於是下定決心要把這個問題搞懂,現在終於把這個問題懟清楚了,分享給大家,希望你們以後面試問到這種問題能有所準備。 Java虛擬機器中描述了兩種異常: 1、如果執

Tomcat中JVM記憶體溢位及合理配置

Tomcat本身不能直接在計算機上執行,需要依賴於硬體基礎之上的作業系統和一個Java虛擬機器。Tomcat的記憶體溢位本質就是JVM記憶體溢位,所以在本文開始時,應該先對Java JVM有關記憶體方面的知識進行詳細介紹。 一、Java JVM記憶體介紹 JVM管理兩種

JVM 記憶體溢位追蹤調優與 記憶體溢位、棧溢位原因

出處1:http://www.iteye.com寫java程式時大家一定對一下兩條異常並不陌生: java.lang.OutOfMemoryError: Java heap space java.lang.OutOfMemoryError: PermGen space 尤其當

分享一次解決線上java應用導致JVM記憶體溢位(OOM)的問題

某個線上的應用執行幾天後,總是出現卡死甚至出現OOM的情況。 注:文中圖片可能與描述不符,僅作為演示! 通過Linux的top命令檢視cpu佔比 首先通過top命令檢視,發現某個java程式佔用了較高記憶體: JDK的jps命令確定是哪個j

JVM記憶體溢位詳解(棧溢位,堆溢位,持久代溢位以及無法建立本地執行緒)

寫在前面 記憶體溢位和記憶體洩漏的區別: 記憶體溢位 out of memory,是指程式在申請記憶體時,沒有足夠的記憶體空間供其使用,出現out of memory;比如申請了一個integer,但給它存了long才能存下的數,那就是記

Jvm記憶體溢位的幾種情況

1、java堆溢位 java對用於儲存物件的例項,只要不斷的建立物件,並且保證GC Roots到物件之間有可達路徑來避免垃圾回收機制清除這些物件,那麼在物件數量達到最大堆的容量限制之後機會產生記憶體溢

java JVM 記憶體溢位 64位JDK

新產品釋出,拿來試用。由於本機是win7_x64,但是為方便工作,機器安裝了從32位的JDK1.5一直到64位的JDK1.6的4個JDK。為保證執行時能與大多數人的執行狀況相同,依然採用了32位的jdk1.6來執行產品。 結果,我第一次碰到應用伺服器剛起來就crash的

android 用GridView載入Bitmap 記憶體溢位問題總結

總結二: 1) 要及時回收Bitmap的記憶體 Bitmap類有一個方法recycle(),從方法名可以看出意思是回收。這裡就有疑問了,Android系統有自己的垃圾回收機制,可以不定期的回收掉不使用的記憶體空間,當然也包括Bitmap的空間。那為什麼還需要這個方法呢? Bitmap類的構造方法都是私有的,

Java記憶體溢位問題總結

  使用Java那麼久,在此總結一下Java中常見的記憶體溢位問題以及對應的解決思路 堆溢位 報錯資訊 java.lang.OutOfMemoryError: Java heap space 報錯原因 堆中(新生代和老年代)無法繼續分配物件了; 某些物件的引用

JVM記憶體溢位有什麼優化、具體使用場景

一、Java記憶體回收機制               不論哪種語言的記憶體分配方式,都需要返回所分配記憶體的真實地址,也就是返回一個指標到記憶體塊的首地址。Java中物件是採用new或者反射的方法建

常見jvm記憶體溢位典型案例

-agentlib:hprof=heap=dump,format=b,file=C:\Users\sxp\Desktop\heapDump1.hprof jvm生成快照檔案 1吞吐量優先收集器在硬體提升的情況下由於大物件在更大堆中的頻繁