何謂Java heap, Native memory and Process Size 续2

處理此問題步驟
Java Out of Memory
 
1. 收集與分析verbose gc 的錯誤訊息輸出
??將“verbosegc“參數加入命令提示列啟動Server,這將會將GC 的活動資訊顯示在標準輸出/輸入,轉到stdout/stderr 的檔案中。執行應用程式直到問題再次產生。
??確定在java out of memory 之前,JVM 做如下內容:
??Full GC run:
執行full GC 與所有soft/weak/phantomly reachable 的物件能被移除與這些空間能被回收,在下面網址可以找到更多不同等級物件消耗細項說明:
http://java.sun.com/developer/technicalArticles/ALT/RefObj
你能檢查full GC 在out of memory 訊息之前做,接下來的一個訊息顯示當GC 已經完成(訊息的格式是依照JVM 定義,檢查JVM 的Help message 以了解訊息格式):
[memory ] 7.160: GC 131072K->130052K (131072K) in 1057.359 ms
下面是上面格式的說明(注意:相似格式將會被使用在遍及這份文件):
[memory ] <start>: GC <before>K-><after>K (<heap>K), <total> ms
[memory ] <start> - start time of collection (seconds since jvm start)
[memory ] <before> - memory used by objects before collection (KB)
[memory ] <after> - memory used by objects after collection (KB)
[memory ] <heap> - size of heap after collection (KB)
[memory ] <total> - total time of collection (milliseconds)
然而,這無法使用訊息推斷soft/weak/phantomly reachable objects 被移除。假如GC 演算法是generational 演算法,你會看到verbose 輸出像這樣:
[memory ] 2.414: Nursery GC 31000K->20760K (75776K), 0.469 ms
上述是nursery GC(或young GC)循環將會提升正在執行的objects 從
nursery(或young space)到old space。這個循環不是重要的分析,更詳細項目有關generational 演算法可以在JVM 的文件中找到;假如GC 的循環不是發生在java out of memory,這樣就可能是JVM 的bug。
??Full compaction:
保證JVM 做適當的緊密程度工作,記憶體沒有碎裂,能防止large objects被配置而且引發一個java out of memory 錯誤。Java Objects 需要連續的記憶區塊,假如沒有空的記憶體區塊,那麼JVM 將無法配置一個large objects,它將無法符合任何一個空的區塊。在這個情況下JVM 將會做full compaction,這樣才會有更多連續記憶體區塊能夠符合容納large objects。Compaction 工作包含移動objects(data)從java heap memory 一個區堆到另一個與更新references 到這些objects 的指定的新的位置上。JVM 將不會重排所有objects,除非這是需要的。這是減少GC 循環的暫停時間。我們能否透過verbose gc 訊息檢查出記憶體碎裂的java out of memory。
假如我們看到輸出像下列所示,即使仍有空的java heap 而out of memory 還是會發生,是因為記憶體碎裂的原因。
[memory ] 8.162: GC 73043K->72989K (131072K) in 12.938 ms
[memory ] 8.172: GC 72989K->72905K (131072K) in 12.000 ms
[memory ] 8.182: GC 72905K->72580K (131072K) in 13.509 ms
java.lang.OutOfMemoryError
以上的情況你能夠看出max heap 是被設定128MB 與JVM 丟出out ofmemory 當實體記憶體使用只有72580K,Heap 使用率只有55%。因此,即使當有45%free heap 的時候,在這個案例記憶體碎裂的影響仍會丟出out of
memory。這是JVM 的bug 或是限制。你必需聯絡原廠請求協助。
 
2. 假如JVM 運作是正常的
假如JVM 運作是正常的(的在上述所提及的動作),那麼java out of memory可能是應用程式的問題。這個應用程式可能不斷洩漏一些java memory,可能是會引發這個問題。或者是應用程式使用過多的objects 它需要更多的heapmemory,以下是可以在這個應用程式中做檢查的:
??應用程式的caching:
假如應用程式在記憶體中caches java objects,那麼我們將需要確定這個cache 是否一直在成長;可能需要在cache 中限制objects 的數量。我們能試著降低這個限制看看是否它會降低java heap 使用量。JAVA soft references 像softly reachable objects 一樣使用data caching,當JVM 執行發生out of heap 時,是允許被移除。
??執行過久的objects:
假如在應用系統裡有在Heap 中存在過久的objects,那麼我們可以儘可能地試著降低存在的objects。例如:調校HTTP session timeout 將能幫助更快回收無效session objects。
??Memory leaks:
一個memory leak 的範例是在應用系統中使用database connectionpools。當使用connection pools,JDBC statement 與resultset objects必需確定最後有被關閉。這基於事實,這由於從pool 中的connection
objects 使用呼叫close(),將簡單connection 傳回到pool 以提供重新使用,若沒有真正關閉connection 與關聯到的statement/resultset
objects。
??增加java heap:
我們也能試著增加java heap 假如可能的話看是否能解決問題。
 
3. 假如不是屬於前兩者的狀況:
那們我們需要使用JVMPI(JVM Profiler Interface)基礎profiler 像Jprobe 或OptimizeIt 去找出那些Objects 是佔住java heap,profilers 也從這些對象正被建立的地方,在java code 裡的細節地方上。這份資料不包括在每profiler 上的細節。profiler 文件可能提到有關如何設定與啟動應用系統與profilers。 通常,基於JVMPI
的profilers 會有過多負擔與大大降低應用系統的效能。因此,在上線環境裡使用這些profilers 是不適當的。
 
For Native OOM Problem:
1. 收集下列資訊
??–verbosegc output to monitor the java heap usage.
這將能幫助了解應用系統的java memory 需求。應用系統它可能會需要獨立使用的實際java heap,在JVM 啟動時預留最大的heap 設定(使用-Xmx 參數在java 命令提示列)與在其他用途是不允許預留記憶體。在這個Jrockit 的案例,使用-verbose 取代-verbosegc 如同在GC 資訊中增加給codegen 資訊。??記錄Process virtual memory size 從應用系統被啟動時,開始在JVM執行到out of native memory;這將能幫助了解不管是process 真的達到作業系統的大小限制。在Windows 的案例,遵照下列程度監控virtual process size:在開始\執行,輸入”perfmon”並且按OK在Performance 圖形上方按下“+“按鍵選擇下面項目:
效能物件: Process (不是預設的processor)
從清單選取計數器: Virtual Bytes
從清單選擇例項: Select the JVM (java) instance
按 “新增”, 並且 “關閉”
在Unix 或Linux 中對於PID 而言,virtual memory size 能夠使用這個命令看到:– ps –p <PID> -o vsz.
在Linux 中每一個java thread 都會有單一個JVM instance 以process方式顯示,假如我們選擇一個root java process 的PID,這個root javaprocess 可以使用ps 命令加上-forest 參數能夠被發現,例如:ps –IU
<user> --forst 將會顯示某一特定使用者所有process 的ASCII 的樹狀結構顯示,你還可以從這樹狀結構找到root java。
 
2. 機器上可用的記憶體
假如機器RAM 與swap space 是不足,那麼作業系統將無法提供更多的記憶體給process,那麼也可能造成out of memory 的結果,確定同機器上的RAM
與swap space 在硬碟空間的加總是足夠執行所有的Process。

3. Java heap 調校
假如java heap 的使用都在max heap 之內,那麼可以考慮降低max heap的大小,以提供更多的native memory 給JVM 使用。這並不是一個解決方案,但是一個測試的變通方法。因為作業系統限定process 大小,我們需要在javaheap 與native heap 之間達到一個平衡。
 
4. JVM 的Native memory 使用量
在所有的classes 被載入JVM 的Native memory 使用量是將可預期會趨於平穩,並且方法已被呼叫(code 的產生已經結束)。應用系統通常發生在最初的幾個小時,在那之後,JVM 可能在執行時載入class,code 的最佳化只需要很小的native memory。
為了減少問題,試著取消執行時最佳化並且檢查是否有何不同。??在這個jrockit 案例,參數-Xnoopt 能夠取消執行時最佳化。在SUN的JVM,參數-Xint 將強制JVM執行在interpreted mode(nocode generation)。假如執行時native memory 使用量仍持續成長,那麼問題就可能是在native
code 這邊發生。
5. 應用程式中Third party 的native modules 或JNI code
檢查不論你是使用Third party 的native module 像是database driver,這些native modules 可能也會配置native memory 並且漏洞可能就是這些modules。基於縮小問題,你能試著重建問題在不使用協助廠商的driver,例如:你能使用pure java drivers 取代native database drivers。檢查你的應用系統是否使用JNI 的程式碼,這也可能造成native memory洩漏,並且你也可以嘗試執行應用系統儘量不使用JNI 程式碼。
6. 假如照上述步驟仍無法找出native memory 問題
那麼你就得向JVM 廠商取得能偵測native memory 配置的特別的版本並且更多有關JVM 上有關記憶體洩漏的訊息。
結論
系統開發時往往問題發生out of memory,或記憶體一直成長無法透過GC回到平均值時,這往往不知道該如何處理此問題所在,到底是應用系統問題,還是JDK 發生的問題,以上的這些是針對有關Memory leak 問題進行說明的了解,與問題排解原則加以說明,期望日後再碰到此問題能有所參考依據與檢測的方式,以讓此類問題能夠不再發生。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值