淺談JVM之使用JFR解決內(nèi)存泄露
簡(jiǎn)介
雖然java有自動(dòng)化的GC,但是還會(huì)有內(nèi)存泄露的情況。當(dāng)然java中的內(nèi)存泄露跟C++中的泄露不同。
在C++中所有被分配的內(nèi)存對(duì)象都需要要程序員手動(dòng)釋放。但是在java中并不需要這個(gè)過(guò)程,一切都是由GC來(lái)自動(dòng)完成的。那么是不是java中就沒(méi)有內(nèi)存泄露了呢?
要回答這個(gè)問(wèn)題我們首先需要界定一下什么是內(nèi)存泄露。如果說(shuō)有時(shí)候我們不再使用的對(duì)象卻不能被GC釋放的話,那么就可以說(shuō)發(fā)生了內(nèi)存泄露。
一個(gè)內(nèi)存泄露的例子
我們舉一個(gè)內(nèi)存泄露的例子,先定義一個(gè)大對(duì)象:
public class KeyObject {
List<String> list = new ArrayList<>(200);
}
然后使用它:
public class TestMemoryLeak {
public static HashSet<Object> hashSet= new HashSet();
public static void main(String[] args) throws InterruptedException {
boolean flag= true;
while(flag){
KeyObject keyObject= new KeyObject();
hashSet.add(keyObject);
keyObject=null;
Thread.sleep(1);
}
System.out.println(hashSet.remove(new KeyObject()));
}
}
在這個(gè)例子中,我們將new出來(lái)的KeyObject對(duì)象放進(jìn)HashSet中。
然后將keyObject置為空。
但是因?yàn)轭?lèi)變量hashSet還保留著對(duì)keyObject的引用,所以keyObject對(duì)象并不會(huì)被回收。
注意,最后一行我們加了一個(gè)hashSet.remove的代碼,來(lái)使用類(lèi)變量hashSet。
為什么要這樣做呢?這樣做是為了防止JIT對(duì)代碼進(jìn)行優(yōu)化,從而影響我們對(duì)內(nèi)存泄露的分析。
使用JFR和JMC來(lái)分析內(nèi)存泄露
Flight Recorder(JFR)主要用來(lái)記錄JVM的事件,我們可以從這些事件中分析出內(nèi)存泄露。
可以通過(guò)下面的指令來(lái)開(kāi)啟JFR:
java -XX:StartFlightRecording
當(dāng)然我們也可以使用java神器jcmd來(lái)開(kāi)啟JFR:
jcmd pid JFR.dump filename=recording.jfr path-to-gc-roots=true
這里我們使用JMC來(lái)圖形化分析一下上面的例子。

開(kāi)啟JMC,找到我們的測(cè)試程序,打開(kāi)飛行記錄器。

可以看到我們的對(duì)象在飛行記錄器期間分配了4MB的內(nèi)存,然后看到整體的內(nèi)存使用量是穩(wěn)步上升的。
我們什么時(shí)候知道會(huì)有內(nèi)存泄露呢?最簡(jiǎn)單的肯定就是OutOfMemoryErrors,但是有些很隱蔽的內(nèi)存泄露會(huì)導(dǎo)致內(nèi)存使用緩步上漲,這時(shí)候就需要我們進(jìn)行細(xì)致的分析。
通過(guò)分析,我們看到內(nèi)存使用在穩(wěn)步上漲,這其實(shí)是很可疑的。
接下來(lái)我們通過(guò)JVM的OldObjectSample事件來(lái)分析一下。
OldObjectSample
OldObjectSample就是對(duì)生命周期比較長(zhǎng)的對(duì)象進(jìn)行取樣,我們可以通過(guò)研究這些對(duì)象,來(lái)檢查潛在的內(nèi)存泄露。

這里我們關(guān)注一下事件瀏覽器中的Old Object Sample事件,我們可以在左下方看到事件的詳情。
或者你可以使用jfr命令直接將感興趣的事件解析輸出:
jfr print --events OldObjectSample flight_recording_1401comflydeanTestMemoryLeak89268.jfr > /tmp/jfrevent.log
我們看一個(gè)具體的輸出Sample:
jdk.OldObjectSample {
startTime = 19:53:25.607
allocationTime = 19:50:51.924
objectAge = 2 m 34 s
lastKnownHeapUsage = 3.5 MB
object = [
java.lang.Object[200]
]
arrayElements = 200
root = N/A
eventThread = "main" (javaThreadId = 1)
stackTrace = [
java.util.ArrayList.<init>(int) line: 156
com.flydean.KeyObject.<init>() line: 11
com.flydean.TestMemoryLeak.main(String[]) line: 17
]
}
lastKnownHeapUsage是heap的使用大小,從日志中我們可以看到這個(gè)值是一直在增加的。
allocationTime表示的是這個(gè)對(duì)象分配的時(shí)間。
startTime表示的是這個(gè)對(duì)象被dump的時(shí)間。
object表示的是分配的對(duì)象。
stackTrace表示的是這個(gè)對(duì)象被分配的stack信息。
注意,如果需要展示stackTrace信息,需要開(kāi)啟-XX:StartFlightRecording:settings=profile選項(xiàng)。
從上面的日志我們可以分析得出,main方法中的第17行,也就是 KeyObject keyObject= new KeyObject(); 在不斷的創(chuàng)建新的對(duì)象。
從而我們可以進(jìn)行更深層次的分析,最終找到內(nèi)存泄露的原因。
以上就是淺談JVM之使用JFR解決內(nèi)存泄露的詳細(xì)內(nèi)容,更多關(guān)于JVM之使用JFR解決內(nèi)存泄露的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java語(yǔ)言實(shí)現(xiàn)基數(shù)排序代碼分享
這篇文章主要介紹了Java語(yǔ)言實(shí)現(xiàn)基數(shù)排序代碼分享,具有一定借鑒價(jià)值,需要的朋友可以參考下。2017-12-12
springboot結(jié)合JWT實(shí)現(xiàn)單點(diǎn)登錄的示例
本文主要介紹了springboot結(jié)合JWT實(shí)現(xiàn)單點(diǎn)登錄的示例,包括生成Token、驗(yàn)證Token及使用Redis存儲(chǔ)Token,具有一定的參考價(jià)值,感興趣的可以了解一下2025-01-01
使用@Validated和@Valid 解決list校驗(yàn)的問(wèn)題
這篇文章主要介紹了使用@Validated和@Valid 解決list校驗(yàn)的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10
java版簡(jiǎn)單的猜數(shù)字游戲?qū)嵗a
猜數(shù)字游戲是一款經(jīng)典的游戲,該游戲說(shuō)簡(jiǎn)單也很簡(jiǎn)單,說(shuō)不簡(jiǎn)單確實(shí)也很難,那么下面這篇文章主要給大家介紹了java版簡(jiǎn)單的猜數(shù)字游戲的相關(guān)資料,文中給出了詳細(xì)的實(shí)現(xiàn)分析和示例代碼供大家參考學(xué)習(xí),需要的朋友們下面來(lái)一起看看吧。2017-05-05
java搭建ftp/sftp進(jìn)行數(shù)據(jù)傳遞的全過(guò)程
ftp是一種文件傳輸協(xié)議,讓客戶(hù)端和服務(wù)端能夠互相傳遞文件,圖片等數(shù)據(jù),sftp也是一種文件傳輸協(xié)議,但是相比較而言要比f(wàn)tp安全性更好些,但是也有缺點(diǎn)就是傳輸效率低2021-07-07
使用SpringAOP實(shí)現(xiàn)公共字段填充功能
在新增員工或者新增菜品分類(lèi)時(shí)需要設(shè)置創(chuàng)建時(shí)間、創(chuàng)建人、修改時(shí)間、修改人等字段,在編輯員工或者編輯菜品分類(lèi)時(shí)需要設(shè)置修改時(shí)間、修改人等字段,這些字段屬于公共字段,本文將給大家介紹使用SpringAOP實(shí)現(xiàn)公共字段填充功能,需要的朋友可以參考下2024-08-08
Spring Boot 2.X整合Spring-cache(讓你的網(wǎng)站速度飛起來(lái))
這篇文章主要介紹了Spring Boot 2.X整合Spring-cache(讓你的網(wǎng)站速度飛起來(lái)),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09

