因自研的自動化測試工具包含壓測功能,在本身本地代碼開發完畢後進行測試,對目標接口進行1000次訪問,發現idea在執行結束後變的異常卡頓,懷疑是idea工具或者程序代碼存在問題,遂進行排查。
----------------------------------------------------------------------------------------------
本地所用MacBook Pro 2015配置
處理器:i7 2.2GHz
核心數:4
內存:16GB
系統:macOS Mojave
----------------------------------------------------------------------------------------------
先從idea排查開始:
一、打開jdk自帶的jconsole工具,鏈接idea;同時打開活動監控器
啓動idea,能夠看到idea的cpu跟內存消耗並不高:
啓動程序,再次觀察cpu跟內存,cpu從2%到了10%,內存增加300M:html
本覺得jconsole能明顯看到jvm的變化狀況,結果否則,並且顯示的數值很小,只有47兆:
這跟系統的活動監視器的結果明顯不符合嘛,後來發現,jconsole實際把idea跟程序的jvm內存使用都分開了,這個顯示的只是idea的,其實本例中若是要查看內存大小,應該直接監控程序的。這個是程序的執行模塊的內存狀況:
二、執行壓測程序,1000訪問量,第一次執行
idea變得很是卡頓,系統的監控器看到明顯的內存變化:
同時,jconsole看到了明顯的內存跟cpu變化狀況:
堆中老年代old:62M,新生代eden:780M左右,倖存區15M,之因此看到新生代跟倖存區同樣高,是由於這裏顯示的百分比,實際新生代佔用的很是多。這裏多說一句,jvm的各個區的命名也是挺有意思的,新對象剛出生,就叫eden區,eden,,,伊甸園麼,亞當跟夏娃開始的那個地方,這名字挺合適的;而後會有垃圾收集,挺不過去就被回收了,對對象來講這輩子也就算完了,挺過去的話,這條命算是保住了,屬於倖存者,因而到了倖存區(survivor)。但是生活並無結束,接下來仍是有一次次的gc來考驗咱們的對象,不少人沒能堅持下來,最終經歷15次gc而沒被回收的,相對來講年齡也不小了,進入的區域叫老年代(old)。挺有意思。
此次執行結束以後,idea的響應速度仍是能夠的,不是怎麼卡頓。
三、壓測1000訪問量,第二次
從以前的經從來看,就是此次壓測會致使idea很是卡頓,監控器狀況:
執行過程當中跟上次相比,並沒有明顯區別,cpu跟內存均沒有明顯增加,但idea拋出了OOM提示框:
若是修改這幾個參數,修改後的內容將被保存到/Users/nm/Library/Preferences/IntelliJIdea2018/idea.vmoptions中,idea默認讀的配置文件也是這個,而不是安裝目錄的bin下的。
壓測程序執行結束以後,監控器看到的idea佔用cpu依然很高,對idea的操做也會有卡頓(有時比較明顯,也偶爾有相對流暢的):
點擊Memory Dump,信息會被存到idea.vmoptions,而後點擊continue繼續。
jconsole一樣看到了內存跟cpu的增加:
圖表中的15:54左右的內存降低應該是jvm的gc致使,後邊16:10分左右的cpu跟內存暴增而後下降纔是此次壓測的表現。(爲什麼堆內存在16:10會驟降,懷疑可能正好有一次gc,jconsole的vm概要有gc次數,忘了截圖)
idea OOM框dump出的信息保存在$USER_HOME/heapDump_Leak_Supports.zip中,解壓有heapDump.hprof文件,內容以下:
用Memory Analyzer Tool打開這個hprof進行查看:
說是a、b兩部份內容「懷疑有罪」,分別235M跟109M,這兩個都是什麼東西呢?
兩個都是idea本身的一個類的對象com.intellij.openapi.editor.impl.DocumentImpl,看名字是個文檔實現類
到這裏,其實我已經猜出問題出在哪裏了,是日誌!由於我之前把控制檯的輸出設置爲無限制,而爲了本地調試方便,我又把hibernate的日誌也打印了出來,在執行單個案例的時候並不明顯,而若是執行大量案例執行,這個日誌的量就很是大了,屢次壓測1000訪問量後系統產生大量日誌,這些日誌都被做爲文本類的內容被保存了起來,又由於我把控制檯日誌設爲無限,idea不清除這些類對象,最終致使對象愈來愈大,拖垮了idea。
若是檢測的不是idea而是本身的程序,那麼還能夠繼續經過histogram跟dominator_tree進行跟蹤。由於強引用、軟引用、弱引用跟虛引用只有強引用不會被gc,若是屢次gc沒有回收掉,確定有強引用在關聯這個對象,經過支配樹 dominator_tree(展現對象層級關係跟內存佔用百分比)跟Merge Shortest Paths to GC Roots(展現gc樹引用關係圖)能夠慢慢找到強引用的所在,從而定位內存溢出緣由。
四、參數修正
明白了問題所在,那麼進行修復並測試,修改idea的相關參數配置爲:
-Xms512m
-Xmn512m
-Xmx2048m
-XX:ReservedCodeCacheSize=240m
-XX:+UseCompressedOops
-Dfile.encoding=UTF-8
-XX:+UseG1GC //使用G1收集器,好處是並行收集
-XX:+UseNUMA //優先使用速度較快的內存
-XX:SoftRefLRUPolicyMSPerMB=50
-ea
-Dsun.io.useCanonCaches=false
-Djava.net.preferIPv4Stack=true
-Djdk.http.auth.tunneling.disabledSchemes=""
-XX:+HeapDumpOnOutOfMemoryError
-XX:-OmitStackTraceInFastThrow
-Xverify:none
-XX:ErrorFile=$USER_HOME/java_error_in_idea_%p.log
-XX:HeapDumpPath=$USER_HOME/java_error_in_idea.hprof
-javaagent:JetbrainsCrack-3.1-release-enc.jar
主要是將堆內存最小設爲512,最大爲2G,變爲了原來的3倍,而後把gc算法改成了G1,並優化內存讀取爲NUMA。NUMA我也不熟悉,網上查到的結果以下:
numa 是一個 CPU 的特性。SMP 架構下,CPU 的核是對稱,可是他們共享一條系統總線。因此 CPU 多了,總線就會成爲瓶頸。在 NUMA 架構下,若干 CPU 組成一個組,組之間有點對點的通信,相互獨立。啓動它能夠提升性能。
NUMA 須要硬件,操做系統,JVM 同時啓用,才能啓用。Linux 能夠用
numactl 來配置 numa,JVM 經過-XX:+UseNUMA來啓用。
五、執行,查看結果
按照以上步驟,一樣程序啓動後執行兩次請求數量均爲1000的壓測,jconsole如圖:
兩次明顯的內存增加跟cpu消耗,監控器看到的內存狀況:
相比以前,idea的內存增加到了2.5G,cpu在壓測結束後恢復正常。點擊idea使用,沒有在發生卡頓的狀況,可知的確是日誌致使idea卡頓的。而當時idea的cpu消耗亦很高,應該是頻繁gc所致。
固然,我僅僅這麼修改是確定不行的,若是控制檯仍舊是無限,那麼總有一天仍是會oom的,我目前是手動清空控制檯,發現效果也還能夠,會有效。若是不手動清空,則必定要設置控制檯最大行數,或者內存值,防止因日誌而致使的idea卡死現象。
--------------------------------------------------------------------------
對jconsole的使用並不熟練,若有錯誤之處請留言指正,多謝多謝。