JVM實戰(zhàn)系列之CPU100%和內(nèi)存100%排查
1. 基礎(chǔ)概念
- 內(nèi)存溢出(Memory Overflow)指的是程序在申請內(nèi)存時,向操作系統(tǒng)申請了一塊內(nèi)存空間,但由于某種原因(如程序錯誤、缺乏足夠的內(nèi)存等),導(dǎo)致程序使用的內(nèi)存超過了申請到的內(nèi)存大小。這會導(dǎo)致程序崩潰或者出現(xiàn)未定義的行為。
- 內(nèi)存泄漏(Memory Leak)指的是程序在動態(tài)分配內(nèi)存后,沒有及時釋放已經(jīng)不需要的內(nèi)存空間,導(dǎo)致系統(tǒng)中存在大量無用的內(nèi)存占用,最終可能會導(dǎo)致系統(tǒng)的性能下降或者耗盡可用內(nèi)存資源。
可以這樣理解:內(nèi)存溢出是指程序需要的內(nèi)存超過了可用內(nèi)存;而內(nèi)存泄漏則是指程序本身的內(nèi)存管理不當(dāng),使用了系統(tǒng)提供的內(nèi)存卻沒有及時釋放。
2. 內(nèi)存100%案例
堆內(nèi)存溢出代碼示例:
private static List<byte[]> CACHE = new ArrayList<>(1000); @GetMapping("/tuningTest") public String tuningTest(){ for (int loopTimes = 1; loopTimes < 20; loopTimes++) { long cacheSize = ObjectSizeCalculator.getObjectSize(CACHE); LOGGER.info("第 {} 次循環(huán)前, 對象已占用 {} M 內(nèi)存", loopTimes, cacheSize / 1024 / 1024); // 每次占用5M內(nèi)存 CACHE.add(new byte[5 * 1024 * 1024]); } return "OK"; }
啟動參數(shù):java -jar -Xms32m -Xmx64m -XX:PermSize=15M -XX:MaxPermSize=30M jvmtest-0.0.1-SNAPSHOT.jar
測試時為了效果明顯可以用壓測工具,并發(fā)數(shù)20,輪次1000。更有助于分析問題
2.1 top 命令查看cpu和內(nèi)存情況
2.2 jmap -heap PID查看jvm內(nèi)存使用情況
從圖中可以看出老年區(qū)的內(nèi)存使用率已經(jīng)達(dá)到了96%
2.3 jstat -gc PID 查看GC的情況
- YGC : YG GC的次數(shù)
- YGCT:YG GC的平均時間
- FGC: FULL GC的次數(shù)
- FGCT:FULL GC的平均時間
這里可以連續(xù)看幾次就會發(fā)現(xiàn)FULL GC的次數(shù)在瘋狂增長,而且FULL GC的平均時間也會增長,這就是CPU100%的原因,因為CPU一直在嘗試?yán)厥?/p>
2.4 jmap -dump:format=b,file=./jmap_dump.hprof PID 使用jmap命令生成分析所需要用的dump文件。
使用Jprofiler打開(為什么不用mat,因為我沒安裝上,不知道為啥)
如上圖已經(jīng)定位出來了問題,這個工具還是很好用的,有興趣的大佬們可以研究研究
3. CPU100%案例
代碼示例
/** * 死循環(huán) * * @return */ @RequestMapping("/deadCycle") public String deadCycle() { for (int i = 1; i > 0; i++) { System.out.println(i); } return "Success"; } /** * 死鎖 * * @return */ @RequestMapping("/deadLock") public String deadLock() { Lock lock1 = new ReentrantLock(); //線程t1中 new Thread(() -> { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } while (!lock1.tryLock()) { System.out.println("線程1 一直自旋獲取鎖"); } System.out.println("線程1 獲取到鎖 do something"); }).start(); // 線程2 new Thread(() -> { lock1.lock(); //此時線程2 獲取到鎖 但是一直阻塞 導(dǎo)致鎖無法釋放 while (true) { } }).start(); return "Success"; }
這里就整一個最簡單里例子,目的就是為了讓CPU一直在運算。
3.1 top 命令查看CPU占用100%的進(jìn)程號
3.2 top -H -n 1 -p PID 然后通過命令查找對應(yīng)進(jìn)程下線程的狀態(tài)
3.3 然后通過 jstack -l PID > ./jstack.log 命令輸出進(jìn)程的線程文件
jstack.log的文件PID是十六機制,從3.2步驟中我們可以看出PID為25778的線程CPU特別高,25778二機制為0x64b2。拿到16進(jìn)制去文件里搜索能夠很明確看出哪里出現(xiàn)了問題
到此這篇關(guān)于JVM實戰(zhàn)系列之CPU100%和內(nèi)存100%排查的文章就介紹到這了,更多相關(guān)JVM CPU100%和內(nèi)存100%排查內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
mybatis-plus添加數(shù)據(jù)時id自增問題及解決
這篇文章主要介紹了mybatis-plus添加數(shù)據(jù)時id自增問題及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-01-01SpringBoot使用RabbitMQ延時隊列(小白必備)
這篇文章主要介紹了SpringBoot使用RabbitMQ延時隊列(小白必備),詳細(xì)的介紹延遲隊列的使用場景及其如何使用,需要的小伙伴可以一起來了解一下2019-12-12Java實現(xiàn)簡易生產(chǎn)者消費者模型過程解析
這篇文章主要介紹了Java實現(xiàn)簡易生產(chǎn)者消費者模型過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-06-06Mybatis自關(guān)聯(lián)查詢一對多查詢的實現(xiàn)示例
這篇文章主要介紹了Mybatis自關(guān)聯(lián)查詢一對多查詢的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-02-02淺談Java虛擬機對內(nèi)部鎖的四種優(yōu)化方式
這篇文章主要介紹了淺談Java虛擬機對內(nèi)部鎖的四種優(yōu)化方式,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-10-10