1. 程式人生 > 其它 >jvm 記憶體調優生產實踐分析

jvm 記憶體調優生產實踐分析

1.用到的工具主要有:jvisualvm  ,IBM HeapAnalyer(主要是堆分析工具)(下載地址:https://www.ibm.com/support/pages/ibm-heapanalyzer)java -jar ha457.jar

2.業務場景說明:公司商城product 模組突然某一天(之前執行的是平穩的)堆記憶體一直在慢慢飆升,最後直接導致 out of memoey。

3.解決分析思路:

排查分析

現象分析

發現現象: Old區爆滿,Eden區爆滿

Old區爆滿屬於不太正常的現象,通常情況下大多數物件會在Eden區就被回收,能進入Old區的物件是較少的,因此要麼是併發量過大,系統不足以支撐這樣的併發,要麼是系統存在無法回收的物件致使Old被撐爆也就是疑似記憶體洩漏。

驗證分析

在懷疑係統中存在記憶體洩漏問題後開始排查程式碼是否存在可能的記憶體洩漏問題,發現一處可能的地點,針對這一部分進行壓力測試

開始設定執行緒數為50,爆記憶體,之後將執行緒數設定為25,Old區穩定在高位(800-1000M左右),在壓力卸掉後Old區依舊穩定在較高位置(600M),較為符合記憶體洩漏表現

進一步驗證

多次進行壓力測試後發現現象穩定復現,再對同一模組其他介面進行壓測,發現出現同樣的現象,對堆記憶體進行dump後發現堆記憶體中存在佔用空間極大的byte[]物件,每個陣列物件開闢了10008208個物件空間。

改進壓測思路,先進行10個執行緒的壓測,待記憶體穩定後進行25個執行緒的壓測,待記憶體穩定後再次切換會10個執行緒的壓測,發現Old區空間穩定在25個執行緒時的水平,沒有繼續增加,遂懷疑與系統中的最大連線相關。

再次分析

使用ha對堆dump進行分析後發現所有的byte[]物件都是被org.apache.coyote.Request物件持有的,懷疑是tomcat導致的現象,因此考慮替換web容器進行對比測試

再次驗證

替換web容器為undertow進行壓測,發現所有介面壓測是Old區都維持在較低水平(80-120M)且在壓力卸掉後Old能回收到50-60M左右,確定是tomcat導致的Old區高佔用

深入分析

之前只是看到記憶體中存在大容量的byte[]物件,並沒有看到其中的內容,因此改用MAT繼續檢視堆dump,這次看到這些byte[]中儲存的是請求相關的資訊

 GET /o2ostock/getByBarcodes?storeLatitude=22.534576&storeLongitude=113.973016&cityId=873&barcodes=0000035&barcodes=0000151 HTTP/1.1..content-type:application/json;charset=UTF-88..accept:*/**..user-agent:Java/1.8.0_1811..host:test21133.star365.com:90166..co... 

發現雖然分配了10008208個空間,但實際使用的遠沒有這麼大,絕大部分的空間是儲存的0,其次是物件雖然很大,但數量卻不多。

接著檢視執行緒相關資訊,發現http-nio-9016-exce-xx執行緒的數量與這個物件的數量一致。

搜尋了tomcat相關的資訊並且閱讀了相關部分的程式碼,懷疑是每個tomcat的工作執行緒持有一個org.apache.coyote.Request物件,而這個物件又持有一個byte[]物件,與科總溝通後發現配置中有這麼一條配置與byte[]物件的大小十分接近

server.max-http-header-size=10000000

將配置改為1000000後再次對product模組進行壓測,Old區在50個執行緒時維持在160M左右,基本可以確定該配置影響了伺服器資源

分析dump 檔案找到佔用最多記憶體的物件和實體類

 

壓測看堆記憶體變化

 

壓測圖:

 

總結:jvm記憶體排查問題是需要不斷猜測和結合排查工具慢慢的區查詢,發現問題所在的,並不是一下子就能找到解決,需要我們靜心,仔細的去發現問題,這個過程是比較有意義的,願天下所有的程式設計師能無jvm問題。