Java 可視化垃圾回收_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
Ben Evans是一名資深培訓(xùn)師兼顧問,他在演講可視化垃圾回收中從基礎(chǔ)談起討論了垃圾回收。
以下是對其演講的簡短總結(jié)。
基礎(chǔ)
當(dāng)談到釋放不再使用的內(nèi)存,垃圾回收已經(jīng)在很大程度上取代了早期技術(shù),比如手動(dòng)內(nèi)存管理和引用計(jì)數(shù)。
這是件好事,因?yàn)閮?nèi)存管理令人厭煩,學(xué)究式地簿記是計(jì)算機(jī)擅長的,而不是人擅長的。在這方面,語言的運(yùn)行時(shí)環(huán)境比人強(qiáng)。
現(xiàn)代的垃圾回收非常高效,遠(yuǎn)遠(yuǎn)超過早期語言中典型的手工分配。通常,具有其它語言背景的人只盯著垃圾回收造成的中斷,卻沒有完全理解自動(dòng)內(nèi)存管理發(fā)生作用的上下文環(huán)境。
標(biāo)記&清除是Java(及其它運(yùn)行時(shí)環(huán)境)用于垃圾回收的基本算法。
在標(biāo)記&清除算法中,引用會(huì)從每個(gè)線程棧的楨指向程序的堆。所以,從棧開始,循著指針找到所有可能的引用,然后再循著這些引用遞歸下去。
當(dāng)遞歸完成,就找到了所有的活對象,其它的都是垃圾。
請注意,人們經(jīng)常漏掉的一點(diǎn)是,運(yùn)行時(shí)環(huán)境本身也有一個(gè)“分配清單(allocation list)”,上面列出了指向每個(gè)對象的指針,該列表由垃圾回收器負(fù)責(zé)維護(hù),并幫助垃圾回收器進(jìn)行垃圾清理。因此,運(yùn)行時(shí)環(huán)境總是可以找出由它創(chuàng)建但尚未回收的對象。

圖一
上面插圖中所示的棧只是一個(gè)與單個(gè)應(yīng)用程序線程相關(guān)的棧;每個(gè)應(yīng)用程序線程都有一個(gè)類似的棧,每個(gè)棧本身都有一組指向堆的指針。
如果垃圾回收器試圖在應(yīng)用程序運(yùn)行過程中獲取活對象的快照,那么它就要追蹤運(yùn)動(dòng)著的目標(biāo),那樣很容易漏掉一些嚴(yán)重超時(shí)的對象分配,因而無法獲得一個(gè)準(zhǔn)確的快照。因此,“Stop the World”是有必要的;也就是,停止應(yīng)用程序線程足夠長的時(shí)間,以便捕獲活對象的快照。
下面是垃圾回收器必須遵循的兩條黃金法則:
垃圾回收器必須回收所有的垃圾。 垃圾回收器必須從不回收任何活對象。
但這兩條規(guī)則并不是對等的;如果違反了第二條規(guī)則,結(jié)果會(huì)使數(shù)據(jù)遭到破壞。
另一方面,如果違反了第一條規(guī)則,則會(huì)是另一種情況,系統(tǒng)并不總是能夠回收所有的垃圾,但最終會(huì)回收所有的垃圾,那么這是可以接受的,而實(shí)際上,這是垃圾回收器的基本原理。
HotSpot
現(xiàn)在,我們來說下HotSpot,它實(shí)際上是一個(gè)C、C++以及許多特定于平臺的匯編程序組成的混合體。
當(dāng)人們想到解釋器,就會(huì)想到一個(gè)很大的while循環(huán),其中包含一個(gè)很長的switch語句。但HotSpot解釋器比那個(gè)要復(fù)雜的多(由于性能原因)。在開始閱讀JDK源代碼的時(shí)候,就會(huì)發(fā)現(xiàn)HotSpot中實(shí)在是有許多匯編程序代碼。
對象創(chuàng)建
Java會(huì)預(yù)先分配大量的連續(xù)空間,就是我們所說的“堆”。之后,HotSpot完全在用戶空間里管理這塊內(nèi)存。
如果一個(gè)Java進(jìn)程占用了大量的系統(tǒng)(或內(nèi)核)時(shí)間,那么毫無疑問,它不是在進(jìn)行垃圾回收——因?yàn)樗械睦厥諆?nèi)存“簿記(bookkeeping)”都是在用戶空間進(jìn)行的。
內(nèi)存池

圖二
“永久代(PermGen)”是一個(gè)存儲區(qū)域,用于保存那些需要在程序生存期內(nèi)一直存活的東西,如類的元數(shù)據(jù)。不過,隨著應(yīng)用程序服務(wù)器的出現(xiàn),它們有自己的類加載器,并且需要重新加載類的元數(shù)據(jù),永久代作為一個(gè)優(yōu)化決策開始顯得糟糕,所幸,它在Java 8中消失了。
Java 8將會(huì)使用一個(gè)名為“元空間(Metaspace)”的新概念。元空間與永久代并不完全相同。它在堆的外面,由操作系統(tǒng)管理。這意味著,它不會(huì)在Java堆中,而是在本地內(nèi)存里。目前,這還不是一個(gè)非常好的消息,因?yàn)闆]有多少工具能夠讓用戶輕松地查看本地內(nèi)存。所以,永久代消失是件好事,但工具趕上這個(gè)變化還需要一些時(shí)間。
Java堆布局
現(xiàn)在,我們來看下Java堆。注意堆空間之間的虛擬空間。它們提供了一點(diǎn)浮動(dòng)量,以允許對內(nèi)存池進(jìn)行一定量的尺寸調(diào)整,又不用為任何對象移動(dòng)付出代價(jià)。

圖三
“弱代假設(shè)(Weak Generational Hypothesis)”
就現(xiàn)狀而言,究竟為什么要將堆分成所有這些內(nèi)存池?

圖四
有的運(yùn)行時(shí)事實(shí)無法通過靜態(tài)分析推導(dǎo)出來。上面的插圖說明有兩組對象:一組存活時(shí)間短,一組存活時(shí)間長——所以,做額外的簿記以便利用這一事實(shí)是有意義的。在Java平臺中,有許多類似的作為優(yōu)化寫入平臺的事實(shí)。
演示
Ben Evans進(jìn)行了一系列的動(dòng)畫演示。第一個(gè)演示是個(gè)Flash,說明了對象在Eden區(qū)和一個(gè)新生代Survivor空間之間移動(dòng),并最終進(jìn)入老年代的過程。
圖五是用JavaFX再現(xiàn)了同樣的過程。

圖五
運(yùn)行時(shí)開關(guān)
‘強(qiáng)制性'參數(shù)
-verbose:gc——為用戶輸出一些GC信息 -Xloggc:<文件路徑>——指定日志輸出路徑,要確保磁盤有空間 -XX:+PringGCDetails——為輔助工具提供“最低限度信息(Minimum information)”
——用這個(gè)參數(shù)代替-verbose:gc
--XX:PrintTenuringDistribution——“過早提升(Premature promotion)”信息 基本堆大小參數(shù)-Xms<size>—— 設(shè)置預(yù)留給堆的最小內(nèi)存值 -Xmx<size>—— 設(shè)置預(yù)留給堆的最大內(nèi)存值 -XX:MaxPermSize=<size>——設(shè)置永久代的最大內(nèi)存值
——有利于Spring應(yīng)用程序和應(yīng)用服務(wù)器
以前,我們被教導(dǎo)要把-Xms和-Xmx的值設(shè)的一樣大。不過這已經(jīng)變了。因此,現(xiàn)在可以為-Xms設(shè)置一個(gè)合理范圍內(nèi)較小的值,或者根本就不設(shè)置,因?yàn)槎训倪m應(yīng)能力現(xiàn)在已經(jīng)非常好了。
其它參數(shù)-XX:NewRatio=N -XX:NewSize=N -XX:MaxNewSize=N -XX:MaxHeapFreeRatio -XX:MinHeapFreeRatio -XX:SurvivorRatio=N -XX:MaxTenuringThreshold=N

圖六
為什么要有日志文件
日志文件的好處是能夠用于取證分析,可以使用戶免于為了再現(xiàn)問題而不得不再執(zhí)行一次代碼(如果是一個(gè)罕見的生產(chǎn)環(huán)境錯(cuò)誤,那么重現(xiàn)并不容易)。
另外,它們包含的信息比針對內(nèi)存的JMX MXBeans所能提供的信息更多,且不說輪詢JMX本身會(huì)引入一系列GC問題。
工具
HP JMeter(用Google查詢一下)
——免費(fèi),非??煽?,但不再提供支持/功能增強(qiáng)
GCViewer
——免費(fèi),開源,但界面有點(diǎn)丑
GarbageCat
——名字最好聽
IBM GCMV
——支持J9
jClarity Censum
——界面最美觀,而且最有用——不過,這是我們的偏見!
小結(jié)
- 需要了解一些GC基礎(chǔ)理論
- 要讓新生代的大部分對象在年輕時(shí)死亡
- 打開GC日志!——原始日志文件難以閱讀——使用工具
- 使用工具來幫助自己調(diào)優(yōu)——測量,而不是猜測
以上所述是小編給大家介紹的Java 可視化垃圾回收,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!
相關(guān)文章
Java使用FilenameFilter查找出目錄下指定后綴的文件示例
這篇文章主要介紹了Java使用FilenameFilter查找出目錄下指定后綴的文件,結(jié)合實(shí)例形式分析了java基于FilenameFilter類的文件遍歷、查找相關(guān)操作技巧,需要的朋友可以參考下2019-10-10
利用Java發(fā)送郵件的實(shí)現(xiàn)代碼
這篇文章給大家分享了如何利用Java發(fā)送郵件,文章通過實(shí)例代碼介紹的很詳細(xì),有需要的可以參考借鑒。2016-08-08
Java數(shù)據(jù)結(jié)構(gòu)之鏈表的增刪查改詳解
在這篇文章中,小編將帶大家了解一下Java數(shù)據(jù)結(jié)構(gòu)中鏈表的增刪查改(以下結(jié)果均在IDEA中編譯)希望在方便自己復(fù)習(xí)的同時(shí)也能幫助到大家2022-09-09
SpringBoot發(fā)送異步郵件流程與實(shí)現(xiàn)詳解
這篇文章主要介紹了SpringBoot發(fā)送異步郵件流程與實(shí)現(xiàn)詳解,Servlet階段郵件發(fā)送非常的復(fù)雜,如果現(xiàn)代化的Java開發(fā)是那個(gè)樣子該有多糟糕,現(xiàn)在SpringBoot中集成好了郵件發(fā)送的東西,而且操作十分簡單容易上手,需要的朋友可以參考下2024-01-01
java開發(fā)ExecutorService監(jiān)控實(shí)現(xiàn)示例詳解
這篇文章主要為大家介紹了java開發(fā)ExecutorService監(jiān)控實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07
SpringSecurity request過濾問題示例小結(jié)
這篇文章主要介紹了SpringSecurity request過濾問題示例小結(jié),本文通過示例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2024-02-02
java數(shù)據(jù)結(jié)構(gòu)基礎(chǔ):單,雙向鏈表
這篇文章主要介紹了Java的數(shù)據(jù)解構(gòu)基礎(chǔ),希望對廣大的程序愛好者有所幫助,同時(shí)祝大家有一個(gè)好成績,需要的朋友可以參考下,希望能給你帶來幫助2021-07-07
spring boot實(shí)現(xiàn)阿里云視頻點(diǎn)播上傳視頻功能(復(fù)制粘貼即可)
這篇文章主要介紹了spring boot實(shí)現(xiàn)阿里云視頻點(diǎn)播上傳視頻功能(復(fù)制粘貼即可),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12

