在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

深入理解Java 8內(nèi)存管理機(jī)制及故障排查實(shí)戰(zhàn)指南

OSC開源社區(qū) ? 來(lái)源:OSC開源社區(qū) ? 2024-04-04 08:10 ? 次閱讀

作者:vivo 互聯(lián)網(wǎng)服務(wù)器團(tuán)隊(duì)- Zeng Zhibin

介紹Java8虛擬機(jī)的內(nèi)存區(qū)域劃分、內(nèi)存垃圾回收工作原理解析、虛擬機(jī)內(nèi)存分配配置,介紹各垃圾收集器優(yōu)缺點(diǎn)及場(chǎng)景應(yīng)用、實(shí)踐內(nèi)存故障場(chǎng)景排查診斷,方便讀者面臨內(nèi)存故障時(shí)有一個(gè)明確的思路和方向。

一、背景

Java是一種流行的編程語(yǔ)言,可以在不同的操作系統(tǒng)上運(yùn)行。它具有跨平臺(tái)、面向?qū)ο蟆⒆詣?dòng)內(nèi)存管理等特點(diǎn),Java程序在運(yùn)行時(shí)需要使用內(nèi)存來(lái)存儲(chǔ)數(shù)據(jù)和程序狀態(tài)。

Java的自動(dòng)內(nèi)存管理機(jī)制是由 JVM 中的垃圾收集器來(lái)實(shí)現(xiàn)的,垃圾收集器會(huì)定期掃描堆內(nèi)存中的對(duì)象,檢測(cè)并清除不再使用的對(duì)象,以釋放內(nèi)存資源。

Java的自動(dòng)內(nèi)存管理機(jī)制帶來(lái)了許多好處,首先,它可以避免程序員手動(dòng)管理內(nèi)存時(shí)的錯(cuò)誤,例如內(nèi)存泄漏和懸空指針等問(wèn)題。其次,它可以提高程序的運(yùn)行效率,因?yàn)槌绦騿T不需要頻繁地手動(dòng)分配和釋放內(nèi)存,而是可以將更多時(shí)間和精力專注于程序的業(yè)務(wù)邏輯,最后,它可以提高程序的可靠性和穩(wěn)定性,因?yàn)槔占骺梢宰詣?dòng)檢測(cè)和清除不再使用的內(nèi)存資源,避免內(nèi)存溢出等問(wèn)題。

了解和掌握垃圾收集器原理可以幫助提高程序的性能、穩(wěn)定性和可維護(hù)性。

名詞解釋:

響應(yīng)速度:響應(yīng)速度指程序或系統(tǒng)對(duì)一個(gè)請(qǐng)求的響應(yīng)有多迅速。比如,用戶查詢數(shù)據(jù)響應(yīng)時(shí)間,對(duì)響應(yīng)速度要求很高的系統(tǒng),較大的停頓時(shí)間是不可接受的。

吞吐量:吞吐量關(guān)注在一個(gè)特定時(shí)間段內(nèi)應(yīng)用系統(tǒng)的最大工作量,例如每小時(shí)批處理系統(tǒng)能完成的任務(wù)數(shù)量,在吞吐量方面優(yōu)化的系統(tǒng),較長(zhǎng)的GC停頓時(shí)間也是可以接受的,因?yàn)楦咄掏铝繎?yīng)用更關(guān)心的是如何盡可能快地完成整個(gè)任務(wù),不考慮快速響應(yīng)用戶請(qǐng)求。

GC導(dǎo)致的應(yīng)用暫停時(shí)間影響系統(tǒng)響應(yīng)速度,GC處理線程的CPU使用率影響系統(tǒng)吞吐量。

二、Java8的內(nèi)存管理

2.1 JVM(Java虛擬機(jī))內(nèi)存劃分

Java運(yùn)行時(shí)數(shù)據(jù)區(qū)域劃分,Java虛擬機(jī)在執(zhí)行Java程序時(shí),將其所管理的內(nèi)存劃分為不同的數(shù)據(jù)區(qū)域,每個(gè)區(qū)域都有特定的用途和創(chuàng)建銷毀的時(shí)間。其中,有些區(qū)域在虛擬機(jī)進(jìn)程啟動(dòng)時(shí)就存在,而有些區(qū)域則是隨著用戶線程的啟動(dòng)和結(jié)束而建立和銷毀。這些數(shù)據(jù)區(qū)域包括程序計(jì)數(shù)器、虛擬機(jī)棧、本地方法棧、堆、方法區(qū)等,每個(gè)區(qū)域都有其自身的特點(diǎn)和作用。了解這些數(shù)據(jù)區(qū)域的使用方式和特點(diǎn),可以更好地理解Java虛擬機(jī)的內(nèi)存管理機(jī)制和運(yùn)行原理。

JVM的內(nèi)存區(qū)域劃分可分為:1.堆內(nèi)存空間、2.Java虛擬機(jī)棧區(qū)域、3.程序計(jì)數(shù)器、4.本地方法棧、5.元空間區(qū)域、6.直接內(nèi)存。

acceca06-ece5-11ee-a297-92fbcf53809c.jpg

ace6b422-ece5-11ee-a297-92fbcf53809c.jpg

堆內(nèi)存空間:JVM中占用內(nèi)存空間最大的是堆,平常對(duì)象的創(chuàng)建大部分都是在堆上分配內(nèi)存的,是垃圾回收的主要目標(biāo)和方向。

本地方法棧區(qū)域:Native Mehod Stack與Java虛擬機(jī)棧的作用非常相似,區(qū)別是Java虛擬機(jī)棧為虛擬機(jī)執(zhí)行Java方法或者為字節(jié)碼而服務(wù),本地方法棧是為了Java 虛擬機(jī)棧得到Native方法。

Java虛擬機(jī)棧區(qū)域:負(fù)責(zé)Java的解釋過(guò)程、程序的執(zhí)行過(guò)程、入棧和出棧,它是與線程相關(guān)的,當(dāng)啟動(dòng)一個(gè)新的線程時(shí),Java程序就會(huì)分配一個(gè)Java 虛擬機(jī)棧提供運(yùn)行;Java 虛擬機(jī)棧從方法入棧到具體字節(jié)碼執(zhí)行是一個(gè)雙層棧結(jié)構(gòu),可以棧里包含棧。

程序計(jì)數(shù)器:記錄線程執(zhí)行位置,線程私有,因?yàn)椴僮飨到y(tǒng)不停的調(diào)度,無(wú)法獲取到線程被調(diào)度之前的位置,程序計(jì)數(shù)器提供了這樣一個(gè)線程執(zhí)行位置。

元空間區(qū)域:在原來(lái)的老的Java 7之前劃分中,永久代用來(lái)存放類的元數(shù)據(jù)信息、靜態(tài)變量以及常量池等。在現(xiàn)在Java8后類的元信息存儲(chǔ)在元空間中,靜態(tài)變量和常量池等并入堆中,相當(dāng)于原來(lái)的永久代中的數(shù)據(jù),被元空間和堆內(nèi)存給瓜分了。

直接內(nèi)存:使用了Java 的直接內(nèi)存的API的內(nèi)存,例如緩沖ByteBuffer,可以控制虛擬機(jī)參數(shù)調(diào)整大小,而本地內(nèi)存是使用了native函數(shù)操作的內(nèi)存,是不受JVM管理控制。

堆內(nèi)存空間

JVM回收的主要目標(biāo)是堆內(nèi)存,對(duì)象主要的創(chuàng)建分配內(nèi)存在堆上進(jìn)行,堆可以想象成一個(gè)對(duì)象池子,對(duì)象不停創(chuàng)建放入池子中,而JVM垃圾回收是不停的回收池子中一些被標(biāo)記為可回收對(duì)象的對(duì)象,啟動(dòng)回收線程進(jìn)行打掃戰(zhàn)場(chǎng),當(dāng)回收對(duì)象的速度趕不上程序的創(chuàng)建時(shí),池子就會(huì)立馬滿,當(dāng)滿了之后從而發(fā)生溢出,就是常見(jiàn)的OOM。

GC的速度和堆的內(nèi)存中存活對(duì)象的數(shù)量有關(guān),與堆內(nèi)存所有的對(duì)象無(wú)關(guān),GC的速度和堆內(nèi)存的大小無(wú)關(guān),如一個(gè)4GB大小的堆內(nèi)存和一個(gè)16GB的堆內(nèi)存,只要2個(gè)堆內(nèi)存存活對(duì)象都是一樣多的時(shí)候,GC速度都是基本差不多。每次垃圾回收也不是必須要把垃圾清理干凈,重要的是保證不把正在使用的對(duì)象給標(biāo)記清除掉。

2.2 堆內(nèi)存管理

JVM中占用內(nèi)存空間最大的是堆內(nèi)存,平常對(duì)象的創(chuàng)建大部分都是在堆上分配內(nèi)存的,是Java垃圾回收的主要目標(biāo)和方向、是 Java內(nèi)存管理機(jī)制的核心組成部分,它可以自動(dòng)管理 Java程序的內(nèi)存分配和釋放,Java垃圾收集器可以自動(dòng)檢測(cè)和回收不再使用的內(nèi)存,以便重新分配給其他需要內(nèi)存的程序。這種自動(dòng)內(nèi)存管理的機(jī)制可以提高程序的運(yùn)行效率和可靠性,防止因內(nèi)存泄漏等問(wèn)題導(dǎo)致程序崩潰或性能下降,Java 垃圾收集器使用了不同的垃圾回收算法和垃圾收集器實(shí)現(xiàn),以適應(yīng)不同的應(yīng)用場(chǎng)景和需求。Java垃圾收集器的性能特征和優(yōu)化技術(shù)也是 Java程序員需要了解和掌握的重要知識(shí)。

因此,了解 Java垃圾回收的背景、原理和實(shí)踐經(jīng)驗(yàn)對(duì)于編寫高效、可靠的 Java程序非常重要。

2.2.1 對(duì)象如何被判斷為可回收

JVM怎么判斷堆內(nèi)存里面的對(duì)象是否可回收的,就是當(dāng)一個(gè)對(duì)象沒(méi)有任何引用指向它了,它就是可回收對(duì)象,判斷的方式有兩種算法,一個(gè)是引用計(jì)數(shù)法,一個(gè)是可達(dá)性分析法。

可回收對(duì)象:

acffb346-ece5-11ee-a297-92fbcf53809c.jpg

(1)引用計(jì)數(shù)法

給對(duì)象中添加一個(gè)引用計(jì)數(shù)器,每當(dāng)有一個(gè)地方引用它時(shí),這個(gè)計(jì)數(shù)器值加一,當(dāng)引用失效斷開時(shí),計(jì)數(shù)器值就減一,在任何時(shí)刻時(shí)計(jì)數(shù)器為0的時(shí)候,代表這個(gè)對(duì)象是可以被回收的,沒(méi)有任何引用使用它了。

ad0f2114-ece5-11ee-a297-92fbcf53809c.jpg

引用計(jì)數(shù)法是有缺點(diǎn),當(dāng)對(duì)象直接互相依賴引用時(shí),這些對(duì)象的計(jì)數(shù)器都不能為0,都不能被回收。

(2)可達(dá)性分析法

它使用tracing(鏈路追蹤)方式尋找存活對(duì)象的方法,通過(guò)一些列稱為“GC Roots”的對(duì)象作為初始點(diǎn),從這些初始點(diǎn)開始向下查找,直到向下查找沒(méi)有任何鏈路時(shí),代表這個(gè)對(duì)象可以被回收,這種算法是目前Java唯一且默認(rèn)使用來(lái)判定可回收的算法。

ad1c19f0-ece5-11ee-a297-92fbcf53809c.jpg

2.2.2 GC Roots的概念和對(duì)象類型

Java 虛擬機(jī)棧中引用的對(duì)象,例如各個(gè)線程被調(diào)用的方法棧用到的參數(shù)、局部變量或者臨時(shí)變量等。

方法區(qū)的靜態(tài)類屬性引用對(duì)象或者說(shuō)Java類中的引用類型的靜態(tài)變量。

方法區(qū)中的常量引用或者運(yùn)行時(shí)常量池中的引用類型變量。

JVM內(nèi)部的內(nèi)存數(shù)據(jù)結(jié)構(gòu)的一些引用、同步的監(jiān)控對(duì)象(被修飾同步鎖)。

JNI中的引用對(duì)象。

當(dāng)然,被GC Roots追溯到的對(duì)象不是一定不會(huì)被垃圾回收,具體需要看情況,Java 對(duì)象與對(duì)象引用存在四種引用級(jí)別:分別是強(qiáng)引用、軟引用、弱引用、虛引用,默認(rèn)的對(duì)象關(guān)系是強(qiáng)引用,只有在和GCRoots沒(méi)有關(guān)系時(shí)才會(huì)被回收;軟引用用于維護(hù)一些可有可無(wú)的對(duì)象,當(dāng)內(nèi)存足夠時(shí)不會(huì)被回收;弱引用只要發(fā)生了垃圾回收就會(huì)被清理;虛引用人如其名形同虛設(shè),任何對(duì)象都與它無(wú)關(guān)。

2.2.3 垃圾對(duì)象回收算法

當(dāng)JVM定位到了那些對(duì)象可回收時(shí),這個(gè)時(shí)候是通過(guò)三個(gè)算法標(biāo)記清除,分別是標(biāo)記清除算法、復(fù)制算法、標(biāo)記壓縮算法。

(1)標(biāo)記清除算法

首先標(biāo)記出所有需要回 收的對(duì)象,在標(biāo)記完成后,統(tǒng)一回收掉所有被標(biāo)記的對(duì)象,但是該算法缺點(diǎn)是執(zhí)行效率低,當(dāng)大量對(duì)象時(shí)需要大量標(biāo)記和清理動(dòng)作,而且容易產(chǎn)生內(nèi)存碎片化,當(dāng)需要一塊連續(xù)內(nèi)存時(shí),會(huì)因?yàn)樗槠療o(wú)法分配。

ad270e32-ece5-11ee-a297-92fbcf53809c.jpg

(2)標(biāo)記壓縮算法

標(biāo)記壓縮算法跟清除算法很像,只不過(guò)它對(duì)內(nèi)存進(jìn)行了整理, 讓存活對(duì)象都向內(nèi)存空間的一端移動(dòng),然后將邊界的其它對(duì)象全部清理,這樣能達(dá)到內(nèi)存碎片化問(wèn)題,不過(guò)它比清除算法多了移步動(dòng)作。

ad3b4b7c-ece5-11ee-a297-92fbcf53809c.jpg

(3)復(fù)制算法

為了解決標(biāo)記-清除算法面對(duì)大量可回收對(duì)象時(shí)執(zhí)行效率低的問(wèn)題,將存活對(duì)象復(fù)制到一塊空置的空間里,然后將原來(lái)的區(qū)域全部清理,缺點(diǎn)是需要額外空間存放存活對(duì)象。

ad4536c8-ece5-11ee-a297-92fbcf53809c.jpg

2.2.4 分代垃圾回收模型概念和原理

堆內(nèi)存分代模型圖

ad5874cc-ece5-11ee-a297-92fbcf53809c.jpg

當(dāng)JVM進(jìn)行GC(垃圾回收)時(shí),JVM會(huì)發(fā)起“Stop the world”,所有的業(yè)務(wù)線程都進(jìn)行停止,進(jìn)入SafePoint狀態(tài),JVM回收垃圾線程開始進(jìn)行標(biāo)記和追溯,如何解決這種停止和如何減少STW的時(shí)間呢?

目前主流垃圾收集器采用分代垃圾回收方式,大部分對(duì)象的聲明周期都比較短,只有少部分的對(duì)象才存活的比較長(zhǎng),分代垃圾回收會(huì)在邏輯上把堆內(nèi)存空間分為兩部分,一部分為年輕代,一部分為老年代。

(1)年輕代空間

年輕代主要是存放新生成的對(duì)象,一般占用堆空間的三分之一空間,因?yàn)闀?huì)頻繁創(chuàng)建對(duì)象,所以年輕代GC頻率是最高的。

分為Eden空間、Survivor1(from)區(qū)、Survivor2(to)區(qū),S1和S2總要有一塊空間是空的,為了方便年輕代存活對(duì)象來(lái)回存放,晉升存活對(duì)象年齡。

三個(gè)區(qū)的默認(rèn)比例是81,可以通過(guò)配置參數(shù)調(diào)整比例。

年輕代回收發(fā)起Minor GC(YongGC),當(dāng)Eden內(nèi)存區(qū)域被占滿之后就發(fā)起GC,短暫的STW,基于垃圾收集器。

(2)老年代空間

是堆內(nèi)存中最大的空間, ,里面的對(duì)象都是比較穩(wěn)定或者老頑固,GC頻率不會(huì)頻繁執(zhí)行。

ad74a750-ece5-11ee-a297-92fbcf53809c.jpg

老年代對(duì)象:

正常提升:由年輕代存活對(duì)象年齡到達(dá)閾值時(shí),這個(gè)對(duì)象則會(huì)被移動(dòng)到老年代中。

分配擔(dān)保:如果年輕代中的空間不足時(shí),此時(shí)有新的對(duì)象需要分配對(duì)象空間,需要依賴其它內(nèi)存進(jìn)行分配擔(dān)保,老年代擔(dān)保直接創(chuàng)建。

大對(duì)象:當(dāng)創(chuàng)建需要大量連續(xù)內(nèi)存空間的對(duì)象時(shí),如長(zhǎng)字符串或者數(shù)組等,大小超過(guò)了閾值時(shí),直接在老年代分配。

動(dòng)態(tài)年齡對(duì)象:有的垃圾收集器不需要到達(dá)指定年齡大小直接晉升老年代,比如相同年齡的對(duì)象的大小總和 > Survivor空間的50%, 年齡大于等于該年齡對(duì)象直接移動(dòng)老年代,無(wú)需等待正常提升。

老年代回收發(fā)起Major GC / FULL GC,當(dāng)老年代滿時(shí)會(huì)觸發(fā)MajorGC,通常至少經(jīng)歷過(guò)一次Minor GC,再緊接著進(jìn)行Major GC, Major GC清理Tenured區(qū),用于回收老年代(CMS才能單獨(dú)清理)。

FUll GC:清除整個(gè)堆空間,一般來(lái)說(shuō)是針對(duì)整個(gè)新生代、老生代、元空間的全局范圍的清理。

不管是Major GC還是 Full GC, STW的耗時(shí)都是Ygc的十倍以上,所以說(shuō)對(duì)象能在年輕代被回收是最優(yōu)的。

Full GC觸發(fā)條件:

老年代空間不足。

元空間不足擴(kuò)容導(dǎo)致。

程序代碼執(zhí)行System.gc時(shí)可能會(huì)執(zhí)行。

當(dāng)程序創(chuàng)建一個(gè)大對(duì)象時(shí),Eden區(qū)域放不下大對(duì)象,老年代內(nèi)存擔(dān)保分配,老年代也不足空間時(shí)。

年輕代存留對(duì)象晉升老年代時(shí),老年代空間不足時(shí)。

2.2.5 Java對(duì)象內(nèi)存分配過(guò)程

ad7ef6b0-ece5-11ee-a297-92fbcf53809c.jpg

對(duì)象的分配過(guò)程

編譯器通過(guò)逃逸分析優(yōu)化手段,確定對(duì)象是否在棧上分配還是堆上分配。

如果在堆上分配,則確定是否大對(duì)象,如果是則直接進(jìn)入老年代空間分配, 不然則走3。

對(duì)比tlab, 如果tlab_top + size <= tlab_end, 則在tlab上直接分配,并且增加tlab_top值,如果tlab不足以空間放當(dāng)前對(duì)象,則重新申請(qǐng)一個(gè)tlab嘗試放入當(dāng)前對(duì)象,如果還是不行則往下走4。

分配在Eden空間,當(dāng)eden空間不足時(shí)發(fā)生YGC, 幸存者區(qū)是否年齡晉升、動(dòng)態(tài)年齡、老年代剩余空間不足發(fā)生Full GC 。

當(dāng)YGC之后仍然不足當(dāng)前對(duì)象放入,則直接分配老年代。

TLAB作用原理:Java在內(nèi)存新生代Eden區(qū)域開辟了一小塊線程私有區(qū)域,這塊區(qū)域?yàn)門LAB,默認(rèn)占Eden區(qū)域大小的1%, 作用于小對(duì)象,因?yàn)樾?duì)象用完即丟,不存在線程共享,快速消亡GC,JVM優(yōu)先將小對(duì)象分配在TLAB是線程私有的,所以沒(méi)有鎖的開銷,效率高,每次只需要線程在自己的緩沖區(qū)分配即可,不需要進(jìn)行鎖同步堆 。

對(duì)象除了基本類型的不一定是在堆內(nèi)存分配,在JVM擁有逃逸分析,能夠分析出一個(gè)新的對(duì)象所擁有的范圍,從而決定是否要將這個(gè)對(duì)象分配到堆上,是JVM的默認(rèn)行為;Java 逃逸分析是一種優(yōu)化技術(shù),可以通過(guò)分析 Java 對(duì)象的作用域和生命周期,確定對(duì)象的內(nèi)存分配位置和生命周期,從而減少不必要的內(nèi)存分配和垃圾回收??梢栽跅I戏峙?,可以在棧幀上創(chuàng)建和銷毀,分離對(duì)象或標(biāo)量替換,同步消除。

public class TaoYiFenxi {
 
    Object obj;
 
    public void setObj() {
        obj = new Object();
    }
 
    public Object getObject() {
        Object obj1 = new Object();
        return obj1;
    }
 
 
    public void test1() {
        synchronized (new Object()) {
 
        }
    }
 
}

2.2.6 JVM垃圾收集器特點(diǎn)與原理

(1)Serial垃圾收集器、Serial Old垃圾收集器

ad884242-ece5-11ee-a297-92fbcf53809c.jpg

Serial收集器采用復(fù)制算法, 作用在年輕代的一款垃圾收集器,串行運(yùn)行,執(zhí)行過(guò)程中會(huì)STW,是使用單個(gè)線程進(jìn)行垃圾回收,響應(yīng)速度優(yōu)先。

Serial Old 收集器采用標(biāo)記整理算法,作用在老年代的一款收集器,串行運(yùn)行,執(zhí)行過(guò)程中會(huì)暫停所有用戶線程,會(huì)STW,使用單個(gè)線程進(jìn)行垃圾回收,響應(yīng)速度優(yōu)先。

使用場(chǎng)景:

適合內(nèi)存小幾十兆以內(nèi),比較適合簡(jiǎn)單的服務(wù)或者單CPU服務(wù),避免了線程交互的開銷。

優(yōu)點(diǎn):

小堆內(nèi)存且單核CPU執(zhí)行效率高。

缺點(diǎn):

堆內(nèi)存大,多核CPU不適合,回收時(shí)長(zhǎng)非常長(zhǎng)。

(2)Parallel Scavenge垃圾收集器、Parallel Old垃圾收集器

ad9eadc0-ece5-11ee-a297-92fbcf53809c.jpg

Parallel Scavenge垃圾收集器采用了復(fù)制算法,作用在年輕代的一款垃圾收集器,是并行的多線程運(yùn)行,執(zhí)行過(guò)程中會(huì)發(fā)生STW,關(guān)注與程序吞吐量。

Parallel Old垃圾收集器采用標(biāo)記整理算法,作用,作用在老年代的一款垃圾收集器, 是并行的多線程運(yùn)行,執(zhí)行過(guò)程中會(huì)發(fā)生STW,關(guān)注與程序吞吐量。

Parallel Scavenge + Parallel Old組合是Java8當(dāng)中默認(rèn)使用的一個(gè)組合垃圾回收。

所謂的吞吐量是CPU用于運(yùn)行用戶代碼時(shí)間與CPU總消耗時(shí)間的比值,也就是說(shuō)吞吐量 = 運(yùn)行用戶代碼時(shí)間 / (運(yùn)行用戶代碼時(shí)間 + 垃圾收集器時(shí)間), 錄入程序運(yùn)行了100分鐘,垃圾收集器花費(fèi)時(shí)間1分鐘,則吞吐量達(dá)到了99%。

使用場(chǎng)景:

適用于內(nèi)存在幾個(gè)G之間,適用于后臺(tái)計(jì)算服務(wù)或者不需要太多交互的服務(wù),保證吞吐量的服務(wù)。

優(yōu)點(diǎn):

可控吞吐量、保證吞吐量,并行收集。

缺點(diǎn):

回收期間STW,隨著堆內(nèi)存增大,回收暫停時(shí)間增大。

(3)Par New垃圾收集器

Par New垃圾收集器采用了復(fù)制算法,作用在年輕代的一款垃圾收集器, 也是并行多線程運(yùn)行,跟Parallel非常相似,是它的增強(qiáng)版本,或者說(shuō)是Serial收集器的多線程版本,是搭配CMS垃圾收集器特制的一個(gè)收集器。

使用場(chǎng)景:

搭配CMS使用

(4)CMS垃圾收集器

CMS是一款多線程+分段操作的一款垃圾收集器。其最大的優(yōu)點(diǎn)就是將一次完整的回收過(guò)程拆分成多個(gè)步驟,并且在執(zhí)行的某些過(guò)程中可以使用戶線程可以繼續(xù)運(yùn)行,分別有初始標(biāo)記,并發(fā)標(biāo)記,重新標(biāo)記,并發(fā)清理和并發(fā)重置。

adaa7d6c-ece5-11ee-a297-92fbcf53809c.jpg

CMS是一款多線程+分段操作的一款垃圾收集器。其最大的優(yōu)點(diǎn)就是將一次完整的回收過(guò)程拆分成多個(gè)步驟,并且在執(zhí)行的某些過(guò)程中可以使用戶線程可以繼續(xù)運(yùn)行,分別有初始標(biāo)記,并發(fā)標(biāo)記,重新標(biāo)記,并發(fā)清理和并發(fā)重置。

CMS分段

初始標(biāo)記階段, 這個(gè)階段會(huì)暫停用戶線程, 掃描所有的根對(duì)象,因?yàn)楦鶎?duì)象比較少,所以一般stw時(shí)間都非常短。

并發(fā)標(biāo)記階段,這個(gè)階段與用戶線程一起執(zhí)行,會(huì)一直沿著根往下掃描,不停的識(shí)別對(duì)象是否為垃圾,標(biāo)記,采用了三色算法, 在對(duì)象頭(Mark World)標(biāo)識(shí)了一個(gè)顏色屬性,不同的顏色代表不同階段,掃描過(guò)程中給與對(duì)象一個(gè)顏色,記錄掃描位置,防止cpu時(shí)間片切換不需要重新掃描。

重新標(biāo)記階段, 這個(gè)階段暫停用戶線程, 修正一些漏標(biāo)對(duì)象,回掃發(fā)生引用變化的對(duì)象。

并發(fā)清理階段, 這個(gè)階段與用戶線程一起執(zhí)行,標(biāo)記清除已經(jīng)成為垃圾的對(duì)象。

三色標(biāo)記

黑色:代表了自己已經(jīng)被掃描完畢,并且自己的引用對(duì)象也已經(jīng)確定完畢。

灰色:代表自己已經(jīng)被掃描完畢了, 但是自己的引用還沒(méi)標(biāo)記完。

白色:則代表還沒(méi)有被掃描過(guò)。

標(biāo)記過(guò)程結(jié)束后,所有未被標(biāo)記的對(duì)象都是不可達(dá)的,可以被回收。

adbc99f2-ece5-11ee-a297-92fbcf53809c.jpg

三色標(biāo)記算法的問(wèn)題場(chǎng)景:當(dāng)業(yè)務(wù)線程做了對(duì)象引用變更,會(huì)發(fā)生B對(duì)象不會(huì)被掃描,當(dāng)成垃圾回收。

public class Demo3 {
 
    public static void main(String[] args) {
        R r = new R();
        r.a = new A();
        B b = new B();
        // GCroot遍歷R, R為黑色, R下面的a引用鏈還未掃完置灰灰色,R.b無(wú)引用, 切換時(shí)間分片
        r.a.b = b;
        // 業(yè)務(wù)線程發(fā)生了引用改變, 原本r.a.b的引用置為null
        r.a.b = null;
        // GC線程回來(lái)繼續(xù)上次掃描,發(fā)現(xiàn)r.a.b無(wú)引用,則認(rèn)為b對(duì)象無(wú)任何引用清除
        r.b = b;
        // GC 回收了b, 業(yè)務(wù)線程無(wú)法使用b
    }
}
 
class R {
    A a;
    B b;
}
 
class A {
    B b;
}
 
class B {
}

adcda896-ece5-11ee-a297-92fbcf53809c.jpg

當(dāng)GC線程標(biāo)記A時(shí),CPU時(shí)間片切換,業(yè)務(wù)線程進(jìn)行了對(duì)象引用改變,這時(shí)候時(shí)間片回到了GC線程,繼續(xù)掃描對(duì)象A, 發(fā)現(xiàn)A沒(méi)有任何引用,則會(huì)將A賦值黑色掃描完畢,這樣B則不會(huì)被掃描,會(huì)標(biāo)記B是垃圾, 在清理階段將B回收掉,錯(cuò)誤的回收正常的對(duì)象,發(fā)生業(yè)務(wù)異常。

CMS基于這種錯(cuò)誤標(biāo)記的解決方案是采取寫屏障 + 增量更新Incremental Update , 在業(yè)務(wù)線程發(fā)生對(duì)象變化時(shí),重新將R標(biāo)識(shí)為灰色,重新掃描一遍,Incremental Update 在特殊場(chǎng)景下還是會(huì)產(chǎn)生漏標(biāo)。

ade2c3b6-ece5-11ee-a297-92fbcf53809c.jpg

public class Demo3 {
 
    public static void main(String[] args) {
        // Incremental Update還會(huì)產(chǎn)生的問(wèn)題
        R r = new R();
        A a = new A();
        A b = new A();
        r.a1 = a;
        // GC線程切換, r掃完a1, 但是沒(méi)有掃完a2, 還是灰色
        r.a2 = b;
        // 業(yè)務(wù)線程發(fā)生引用切換, r置灰灰色(本身灰色)
        r.a1 = b;
        // GC線程繼續(xù)掃完a2, R為黑色, b對(duì)象又漏了~
    }
}
 
class R {
    A a1;
    A a2;
}
 
class A {
}

當(dāng)GC 1線程正在標(biāo)記O, 已經(jīng)標(biāo)記完O的屬性 O.1, 準(zhǔn)備標(biāo)記O.2時(shí),業(yè)務(wù)線程把屬性O(shè),1 = B,這時(shí)候?qū)對(duì)象再次標(biāo)記成灰色, GC 1線程切回,將O.2線程標(biāo)記完成,這時(shí)候認(rèn)為O已經(jīng)全部標(biāo)記完成,O標(biāo)記為黑色, B對(duì)象產(chǎn)生了漏標(biāo), CMS針對(duì)Incremental Update產(chǎn)生的問(wèn)題,只能在remark階段,暫停所有線程,將這些發(fā)生過(guò)引用改變過(guò)的,重新掃描一遍。

使用場(chǎng)景:

適用于互聯(lián)網(wǎng)或者 B/S服務(wù), 響應(yīng)速度優(yōu)先,適合6G左右。

優(yōu)點(diǎn):

并發(fā)收集, 低停頓,回收過(guò)程中最耗時(shí)的是并發(fā)標(biāo)記和并發(fā)清除,它都能與用戶線程保持一起工作。

缺點(diǎn):

收集器對(duì)CPU的資源非常敏感,會(huì)占用用戶線程部分使用,導(dǎo)致程序會(huì)變得緩慢,吞吐量下降。

無(wú)法處理浮動(dòng)垃圾,在并發(fā)清理階段用戶線程還是在運(yùn)行,這時(shí)候產(chǎn)生的新垃圾無(wú)法在這次當(dāng)中處理,只有等待下次才會(huì)清理。

因?yàn)镃MS使用了Incremental Update,remark階段還是會(huì)所有暫停,重新掃描發(fā)生引用改變的GC root,效率慢耗時(shí)高。

因?yàn)槭占魇腔跇?biāo)記清除算法實(shí)現(xiàn)的,所以在收集器回收結(jié)束后,內(nèi)存會(huì)產(chǎn)生碎片化,當(dāng)碎片化非常嚴(yán)重的時(shí)候,這時(shí)候有大對(duì)象進(jìn)入無(wú)法分配內(nèi)存時(shí)會(huì)觸發(fā)FullGC,特殊場(chǎng)景下會(huì)使用Serial收集器,導(dǎo)致停頓不可控。

(5)G1垃圾收集器

G1也是采用三色標(biāo)記分段式進(jìn)行回收的算法, 不過(guò)它是寫屏障 + STAB快照實(shí)現(xiàn),G1設(shè)定的目標(biāo)是在延遲可控(低暫停)的情況下獲得盡可能高的吞吐量,仍然可以通過(guò)并發(fā)的方式讓Java 程序繼續(xù)運(yùn)行,G1垃圾收集器在很多方面彌補(bǔ)了CMS的不足,比如CMS使用的是mark-sweep標(biāo)記清除算法,自然會(huì)產(chǎn)生內(nèi)存碎片(CMS只能在Full GC時(shí),STW 整理內(nèi)存碎片),然而G1整體來(lái)看是基于標(biāo)記整理算法實(shí)現(xiàn)的收集器,但是從局部來(lái)看也是基于復(fù)制算法實(shí)現(xiàn)的,高效的整理剩余內(nèi)存,而不需要管理內(nèi)存碎片它。

G1同樣有年輕代和老年代的概念,只不過(guò)物理空間劃分已經(jīng)不存在,邏輯分區(qū)還存在,G1會(huì)把堆切成若干份,每一份當(dāng)作一個(gè)目標(biāo),在部分上目標(biāo)很容易達(dá)成,G1在進(jìn)行垃圾回收的時(shí)候,將會(huì)根據(jù)最大停頓時(shí)間設(shè)置值動(dòng)態(tài)選取部分小堆區(qū)垃圾回收。

adf81afe-ece5-11ee-a297-92fbcf53809c.jpg

G1的特點(diǎn)是盡量追求吞吐量,追求響應(yīng)時(shí)間,并發(fā)收集,壓縮空閑空間不會(huì)延長(zhǎng)GC暫停時(shí)間,更容易預(yù)測(cè)GC暫停時(shí)間,能充分利用CPU、多核環(huán)境下的硬件優(yōu)勢(shì),使用多個(gè)CPU對(duì)STW進(jìn)行控制(200ms以內(nèi))靈活的分區(qū)回收,優(yōu)先回收花費(fèi)時(shí)間少的或者垃圾比例高的region新老比例也是動(dòng)態(tài)調(diào)整,不需要配置;年齡晉升也是15,但是可以動(dòng)態(tài)年齡,當(dāng)幸存者region超過(guò)了50時(shí),會(huì)把年齡最大的放入老年代。

G1動(dòng)態(tài)Y區(qū)域設(shè)置,G1每個(gè)分區(qū)都可能是年輕代或者老年代,但是同一時(shí)刻只屬于一個(gè)代,分代概念還存在,邏輯上分代方便復(fù)用以前分代邏輯,在物理上不需要連續(xù),這樣能帶來(lái)額外好處,有的分區(qū)內(nèi)垃圾比較多,有的分區(qū)比較少,G1會(huì)優(yōu)先回收垃圾比較多的分區(qū),這樣可以花費(fèi)少量的時(shí)間來(lái)回收這些分區(qū)垃圾,即收集最多垃圾分區(qū);但是新生代回收不適合這種,新生代達(dá)到閾值時(shí)發(fā)生YGC,對(duì)整個(gè)新生代進(jìn)行回收或者晉升幸存,新生代也分區(qū)是方便動(dòng)態(tài)調(diào)整分區(qū)大小,在進(jìn)行垃圾回收時(shí),會(huì)將存活對(duì)象拷貝到另一個(gè)可用分區(qū)上,這樣也能避免一定程度的內(nèi)存碎片化過(guò)程,每個(gè)分區(qū)的大小都是在1M- 32M之間,取決2的冪次方。

Humingous:如果一個(gè)對(duì)象占用的空間超過(guò)了分區(qū)容量50%以上,G1收集器就認(rèn)為這是一個(gè)巨型對(duì)象。這些巨型對(duì)象,默認(rèn)直接會(huì)被分配在年老代,但是如果它是一個(gè)短期存在的巨型對(duì)象,就會(huì)對(duì)垃圾收集器造成負(fù)面影響;為了解決這個(gè)問(wèn)題,G1劃分了一個(gè)Humongous區(qū),它用來(lái)專門存放巨型對(duì)象。如果一個(gè)H區(qū)裝不下一個(gè)巨型對(duì)象,那么G1會(huì)尋找連續(xù)的H分區(qū)來(lái)存儲(chǔ)。為了能找到連續(xù)的H區(qū),有時(shí)候不得不啟動(dòng)Full GC。

CardTable:記錄每一塊card內(nèi)存區(qū)域是否dirty,如果在發(fā)生YGC時(shí),怎么知道那些是存活對(duì)象,并且其它代區(qū)域有沒(méi)有引用這部分對(duì)象,于是把內(nèi)存劃分了很多card區(qū)域, 每個(gè)區(qū)域大小不超過(guò)512b,當(dāng)該card區(qū)域里的對(duì)象有引用關(guān)系,將當(dāng)前card置為“dirty”, 并且使用卡表(CardTable)來(lái)記錄每一塊card是否dirty,在進(jìn)行GC時(shí),不用遍歷所有的空間, 只需要遍歷卡表中為"dirty"或者說(shuō)布爾符合條件的card區(qū)域進(jìn)行回掃。

ae0d0b6c-ece5-11ee-a297-92fbcf53809c.png

CSet:Collection SET用于記錄可被回收分區(qū)的集合組, G1使用不同算法,動(dòng)態(tài)的計(jì)算出那些分區(qū)是需要被回收的,將其放到CSet中,在CSet當(dāng)中存活的數(shù)據(jù)都會(huì)在GC過(guò)程中拷貝到另一個(gè)可用分區(qū),CSet可以是所有類型分區(qū),它需要額外占用內(nèi)存,堆空間的1%。

RSet:RememberedSet 每個(gè)Region都有一個(gè)Rset,是一個(gè)記錄了其他Region中的對(duì)象到本身Region的引用,它可以使得垃圾收集器不需要掃描整個(gè)堆去找到誰(shuí)的引用了當(dāng)前分區(qū)對(duì)象,是G1高效回收的關(guān)鍵點(diǎn),也是三色算法的一個(gè)以來(lái)點(diǎn)。

ae2442be-ece5-11ee-a297-92fbcf53809c.jpg

RSet和卡表的區(qū)別是什么?

卡表記錄的是堆內(nèi)存中card有沒(méi)有變成"dirty", 但是它本身不知道dirty里面哪些是引用了的對(duì)象,它是一個(gè)大維度的一個(gè)記錄,RSet是記錄自身Region中對(duì)象引用了其它Region中的那些對(duì)象,詳細(xì)的記錄對(duì)方引用對(duì)象信息,G1使用了兩者的結(jié)合,實(shí)現(xiàn)了增量式的垃圾回收,并優(yōu)化跨區(qū)引用的最終處理。

SATB算法:是一種基于快照的算法,它可以避免在垃圾回收時(shí)出現(xiàn)對(duì)象漏標(biāo)或者重復(fù)標(biāo)記的問(wèn)題,從而提高垃圾回收的準(zhǔn)確性和效率,在垃圾回收開始時(shí),對(duì)堆中的對(duì)象引用進(jìn)行快照,然后在并發(fā)標(biāo)記階段中記錄下所有被修改過(guò)對(duì)象引用,保存到satb_mark_queue中,最后在重新標(biāo)記階段重新掃描這些對(duì)象,標(biāo)記所有被修改的對(duì)象,保證了準(zhǔn)確性和效率。

SATB算法在remark階段不需要暫停遍歷整個(gè)堆對(duì)象,只需要掃描“satb_mark_queue”隊(duì)列中的記錄,避免了這個(gè)階段長(zhǎng)耗時(shí),而cms的增量算法在這個(gè)階段是需要重新掃描GC Roots標(biāo)記整個(gè)堆對(duì)象,導(dǎo)致了不可控時(shí)間暫停,總的來(lái)說(shuō)G1是通過(guò)回收領(lǐng)域應(yīng)用并行化策略,將原來(lái)的幾塊大內(nèi)存塊回收問(wèn)題,演變成了N個(gè)小內(nèi)存塊回收,使得回收效率可以高度并行化,停頓時(shí)間可控,可以與用戶線程并發(fā)執(zhí)行,將一塊內(nèi)存分而治之。

ae369d7e-ece5-11ee-a297-92fbcf53809c.jpg

G1默認(rèn)當(dāng)分區(qū)內(nèi)存占用閾值達(dá)到總內(nèi)存的45%,會(huì)發(fā)生Mixed gc(混和GC),YoungGC + 并發(fā)回收Mixed GC過(guò)程:初始標(biāo)記(stw)、并發(fā)標(biāo)記、最終標(biāo)記(重新標(biāo)記stw)、篩選回收(stw并行)。

使用場(chǎng)景:

響應(yīng)速度優(yōu)先,較高的吞吐量,面向服務(wù)端,使用內(nèi)存6G以上。

優(yōu)點(diǎn):

并行與并發(fā)收集,分代分區(qū)收集,優(yōu)先垃圾收集,空間整合,可控或者可預(yù)測(cè)停頓時(shí)間。

缺點(diǎn):

收集中產(chǎn)生內(nèi)存,G1的每個(gè)region都需要有一份記憶集和卡表記錄跨代指針,這導(dǎo)致記憶集可能占用堆空間10-20%甚至更多空間。

執(zhí)行過(guò)程中額外負(fù)載開銷加大,寫屏障進(jìn)行維護(hù)卡表操作外,還需要原始快照能夠減少并發(fā)標(biāo)記和重新標(biāo)記階段的消耗,避免最終標(biāo)記階段停頓過(guò)長(zhǎng),運(yùn)行過(guò)程中會(huì)產(chǎn)生由跟蹤引用變化帶來(lái)的額外開銷負(fù)擔(dān),比CMS增量算法消耗更多,CMS的寫屏障實(shí)現(xiàn)直接是同步操作, 而G1是把寫屏障和寫后屏障中要做的事情放到隊(duì)列里異步處理。

G1對(duì)于Full GC是沒(méi)有處理流程, 一旦發(fā)生Full GC G1的回收?qǐng)?zhí)行的是單線程的Serial回收器進(jìn)行回收。

2.2.7 垃圾收集器配置使用

機(jī)器配置:64位 4C8G

Java 程序使用CMS收集器進(jìn)行內(nèi)存垃圾回收初始內(nèi)存劃分情況:

-Xms4096M-Xmx4096M-XX:+HeapDumpOnOutOfMemoryError-XX:HeapDumpPath=/data/{runuser}/logs/other-XX:+UseConcMarkSweepGC

ae4be576-ece5-11ee-a297-92fbcf53809c.png

CMS 跟 parNew占比情況, 默認(rèn)下 ParNew占用整個(gè)堆的空間為:機(jī)器位數(shù) * CPU核數(shù) * 13 /10 , 當(dāng)前機(jī)器配置計(jì)算得出 64 * 4 * 13 / 10 = 332M , 與圖上數(shù)值差別不大。

Java程序使用G1收集器進(jìn)行內(nèi)存垃圾回收初始內(nèi)存劃分情況:

-Xms4096M-Xmx4096M-XX:+HeapDumpOnOutOfMemoryError-XX:HeapDumpPath=/data/{runuser}/logs/other-XX:+UseG1GC

ae61c120-ece5-11ee-a297-92fbcf53809c.png

G1 新老年代的占比是動(dòng)態(tài)調(diào)整, 隨著運(yùn)行時(shí)根據(jù)實(shí)際情況劃分空間。

Java8默認(rèn)ParallerGC收集器初始內(nèi)存劃分情況:

ae78177c-ece5-11ee-a297-92fbcf53809c.png

parallel GC回收器默認(rèn)堆old區(qū)與young區(qū)內(nèi)存大小比例 2:1, 圖上數(shù)值差別不大。

三、內(nèi)存診斷實(shí)踐

3.1 內(nèi)存快照生成

當(dāng)發(fā)生線上應(yīng)用告警,告警相關(guān)內(nèi)存故障問(wèn)題時(shí), 應(yīng)當(dāng)如何進(jìn)行故障排查呢?首先應(yīng)用在發(fā)生內(nèi)存溢出無(wú)法執(zhí)行時(shí),應(yīng)DUMP當(dāng)前內(nèi)存快照,需要在Java程序執(zhí)行啟動(dòng)命令時(shí)添加上:

-XX:+HeapDumpOnOutOfMemoryError

-XX:HeapDumpPath=${filePath} 參數(shù)

當(dāng)發(fā)生時(shí)自動(dòng)生成一份當(dāng)前內(nèi)存快照,方便與開發(fā)人員使用快照文件進(jìn)行問(wèn)題診斷分析。

在Java應(yīng)用運(yùn)行時(shí),想手動(dòng)生成內(nèi)存快照,可以使用JDK自帶幾個(gè)問(wèn)題排查工具,可以使用jmap工具生成指定PID內(nèi)存快照,不過(guò)需要耗費(fèi)較長(zhǎng)的一個(gè)時(shí)間,會(huì)暫停應(yīng)用程序執(zhí)行,使用jcmd工具可以快速的DUMP內(nèi)存快照,因?yàn)樵诙艳D(zhuǎn)儲(chǔ)存文件過(guò)程中,jcmd可以利用虛擬機(jī)中的一些優(yōu)化技術(shù),例如分代堆、增量式垃圾回收等技術(shù),相比傳統(tǒng)的jmap效率高很多,一般來(lái)說(shuō)在DUMP內(nèi)存前會(huì)進(jìn)行一次

Full FC,可以指定屏蔽這次Full GC,保留當(dāng)前所有內(nèi)存中的對(duì)象。

除了自帶的內(nèi)存診斷工具, 也可以使用Arthas診斷工具,提供了多個(gè)命令來(lái)幫助診斷內(nèi)存問(wèn)題,例如 dashboard(當(dāng)前Java程序內(nèi)存實(shí)時(shí)數(shù)據(jù)面板)、JVM(查看當(dāng)前JVM信息,包括使用的gc收集器、內(nèi)存分區(qū)分布情況等信息)、heapdump(當(dāng)前內(nèi)存快照類似jmap命令的heap dump)、memory(當(dāng)前內(nèi)存分區(qū)及占用情況)、monitor(監(jiān)控模式,可監(jiān)控內(nèi)存及查看對(duì)象占用情況)profiler(火焰圖可以輸出多種火焰圖,內(nèi)存分區(qū)占用火焰圖)等相關(guān)內(nèi)存命令。這些命令可以幫助獲取應(yīng)用程序的內(nèi)存快照、堆內(nèi)存使用情況等信息,能快速定位內(nèi)存問(wèn)題。

引用:Arthas 命令列表

3.2 dump內(nèi)存快照分析

(1)jhat 是 Java 開發(fā)工具包自帶的一款堆內(nèi)存分析工具,它可以幫助解決 Java 應(yīng)用程序的內(nèi)存問(wèn)題。Jhat 可以讀取 Java 應(yīng)用程序生成的堆轉(zhuǎn)儲(chǔ)文件,并以 HTML 格式展示內(nèi)存中的對(duì)象信息和引用關(guān)系,支持 OQL 查詢和靈活的過(guò)濾和排序功能。

用例 jhat E:diydumpJava_pid2680.hprof

ae915af2-ece5-11ee-a297-92fbcf53809c.jpg

All classes including platform:列舉應(yīng)用程序中所有類的信息,并快速定位內(nèi)存問(wèn)題。

Show all members of the rootset:顯示堆內(nèi)存中所有根對(duì)象的信息,包括系統(tǒng)對(duì)象、靜態(tài)對(duì)象、本地對(duì)象等。

Show instance counts for all classes (including platform):顯示所有類的實(shí)例數(shù)量。

Show heap histogram:顯示程序堆內(nèi)存的直方圖,可以知道每個(gè)類的實(shí)例數(shù)量和占用內(nèi)存大小等信息,快速知道內(nèi)存泄漏原因。

(2)jvisualvm也是Java 開發(fā)工具包里自帶的一款圖形化工具,可以用于監(jiān)控和診斷Java應(yīng)用程序的性能問(wèn)題。使用它可以實(shí)時(shí)查看Java 應(yīng)用程序的內(nèi)存使用情況、CPU使用情況、線程情況等,并可以進(jìn)行內(nèi)存分析、CPU分析、線程分析等內(nèi)容。

以Java_pid2680.hprof為例,進(jìn)行內(nèi)存分析內(nèi)存泄漏原因:

aea65af6-ece5-11ee-a297-92fbcf53809c.png

(3)MAT 是基于Eclipse的內(nèi)存分析工具,是一個(gè)快速、功能豐富的Java內(nèi)存分析工具,能夠快速的分析出dump文件中各項(xiàng)結(jié)果,快速給出內(nèi)存泄漏原因報(bào)告。

還是以Java_pid2680.hprof文件進(jìn)行分析,比原生的jhat方便很多,功能也比原生的更加豐富:

aebc1b66-ece5-11ee-a297-92fbcf53809c.png

MAT的一些常用功能點(diǎn)介紹(如圖所示):

Overview 標(biāo)簽內(nèi)容有比較多塊內(nèi)容,其中details末塊介紹總共使用內(nèi)存大小,類的數(shù)量,實(shí)例的數(shù)量,類的加載器,以及實(shí)例的內(nèi)存直方圖;

Biggest Objects by Retained Size模塊,使用了餅狀圖列出了當(dāng)前內(nèi)存中占用最大的幾個(gè)對(duì)象,按照百分比劃分,點(diǎn)擊不同的餅狀塊能夠看到具體對(duì)象及其對(duì)象屬性等信息;

actions模塊,這里擁有不同的分析功能,Histogram生成視圖列出每個(gè)類所對(duì)應(yīng)的對(duì)象個(gè)數(shù)以及占用內(nèi)存大小,Dominator Tree生成視圖尋找出大對(duì)象,每個(gè)實(shí)例對(duì)象的內(nèi)存占比比重;

Reports模塊是生成報(bào)告,其中Leak Suspects可以自動(dòng)分析內(nèi)存泄漏主要原因報(bào)告,可以通過(guò)報(bào)告準(zhǔn)確定位泄漏原因或者可能造成泄漏的原因,并且可以定位到具體累積實(shí)例,線程stack等信息。

例子中:leak Suspects報(bào)告給出“0xfe3be480” 非常多內(nèi)存, Gc root Thread 所引用,在發(fā)生gc時(shí),不是可回收對(duì)象,無(wú)法回收內(nèi)存,導(dǎo)致內(nèi)存溢出。

aed3f3da-ece5-11ee-a297-92fbcf53809c.png

四、總結(jié)

本文介紹了Java程序中的內(nèi)存模型,內(nèi)存模型劃分多份內(nèi)存區(qū)域,不同區(qū)域的作用介紹及不同區(qū)域的線程之間的內(nèi)存共享范圍,可以幫助開發(fā)人員更加理解Java 中內(nèi)存管理的機(jī)制和原理。

堆是內(nèi)存模型中最大的一塊內(nèi)存區(qū)域,以堆的空間劃分詳細(xì)的介紹了內(nèi)存分代,部分垃圾收集器即是物理分代和邏輯分代,G1收集器則物理不分代邏輯保留了以前分代,講述了不同收集器的原理實(shí)現(xiàn)和優(yōu)缺點(diǎn),可以根據(jù)項(xiàng)目的業(yè)務(wù)屬性,機(jī)器配置等因素選擇最優(yōu)的收集器,幫助程序使用最優(yōu)的收集器可以使得程序的吞吐量和響應(yīng)速度達(dá)到最佳狀態(tài)。還講述了不同的參數(shù)調(diào)優(yōu)收集器,并且當(dāng)發(fā)生了程序內(nèi)存溢出崩潰,如何進(jìn)行內(nèi)存分析,介紹不同工具的使用,快速定位內(nèi)存溢出的罪魁禍?zhǔn)?,從而在代碼層面上根本解決這類問(wèn)題。

審核編輯:黃飛

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • cpu
    cpu
    +關(guān)注

    關(guān)注

    68

    文章

    11038

    瀏覽量

    216031
  • JAVA
    +關(guān)注

    關(guān)注

    20

    文章

    2984

    瀏覽量

    106924
  • 計(jì)數(shù)器
    +關(guān)注

    關(guān)注

    32

    文章

    2284

    瀏覽量

    96043
  • 內(nèi)存管理
    +關(guān)注

    關(guān)注

    0

    文章

    168

    瀏覽量

    14482
  • 線程
    +關(guān)注

    關(guān)注

    0

    文章

    507

    瀏覽量

    20080

原文標(biāo)題:Java 8內(nèi)存管理原理解析及內(nèi)存故障排查實(shí)踐

文章出處:【微信號(hào):OSC開源社區(qū),微信公眾號(hào):OSC開源社區(qū)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    深入理解Android

    深入理解Android
    發(fā)表于 08-20 15:30

    深入理解和實(shí)現(xiàn)RTOS_連載

    ,那里有更詳細(xì)的注釋,而且是全中文的。深入理解和實(shí)現(xiàn)RTOS_連載5_多任務(wù)機(jī)制應(yīng)用演示本節(jié)我們通過(guò)在評(píng)估板上的實(shí)例來(lái)演示有關(guān)線程調(diào)度和管理的API。因?yàn)槊總€(gè)例子中都包括了線程的創(chuàng)建,所以這里就不單獨(dú)再介紹如何創(chuàng)建線程。示例程序
    發(fā)表于 05-29 11:20

    深入理解和實(shí)現(xiàn)RTOS_連載

    /325438。作者何小慶教授花了很多精力編寫了這組資料。深入理解和實(shí)現(xiàn)RTOS_連載2_多任務(wù)機(jī)制概述在前面我們?cè)榻B了多任務(wù)系統(tǒng)是如何演化的。和前后臺(tái)系統(tǒng)相比較,多任務(wù)可以理解為有多個(gè)后臺(tái)程序的前后臺(tái)系統(tǒng)
    發(fā)表于 05-30 01:02

    深入理解LINUX內(nèi)存管理》學(xué)習(xí)筆記

    深入理解LINUX內(nèi)存管理》學(xué)習(xí)筆記1
    發(fā)表于 11-07 10:20

    怎么給RTOS動(dòng)態(tài)分區(qū)內(nèi)存管理機(jī)制進(jìn)行優(yōu)化?

    怎么給RTOS動(dòng)態(tài)分區(qū)內(nèi)存管理機(jī)制進(jìn)行優(yōu)化?
    發(fā)表于 04-28 06:17

    嵌入式系統(tǒng)所用到的內(nèi)存管理機(jī)制主要有哪幾種

    嵌入式系統(tǒng)所用到的內(nèi)存管理機(jī)制主要有以下兩種: 1、虛擬內(nèi)存管理機(jī)制: 有一些嵌入式處理器提供了MMU,在MMU具備內(nèi)存地址映射和尋址功能,
    發(fā)表于 12-17 06:34

    VxWorks內(nèi)存管理機(jī)制的分析與研究

    實(shí)時(shí)性、可靠性是嵌入式開發(fā)對(duì)內(nèi)存管理的基本要求,本文探討了操作系統(tǒng)內(nèi)存管理的主要問(wèn)題,對(duì)嵌入式操作系統(tǒng)Vxworks 的內(nèi)存
    發(fā)表于 01-07 12:35 ?23次下載

    linux內(nèi)存管理機(jī)制淺析

    本內(nèi)容介紹了arm linux內(nèi)存管理機(jī)制,詳細(xì)說(shuō)明了linux內(nèi)核內(nèi)存管理,linux虛擬內(nèi)存管理
    發(fā)表于 12-19 14:09 ?73次下載
    linux<b class='flag-5'>內(nèi)存</b><b class='flag-5'>管理機(jī)制</b>淺析

    深入理解Linux虛擬內(nèi)存管理_愛(ài)爾蘭/戈?duì)柭?/a>

    電子發(fā)燒友網(wǎng)站提供《深入理解Linux虛擬內(nèi)存管理_愛(ài)爾蘭/戈?duì)柭?txt》資料免費(fèi)下載
    發(fā)表于 02-09 15:19 ?0次下載

    最全SPARK內(nèi)存管理機(jī)制

    最全SPARK內(nèi)存管理機(jī)制
    發(fā)表于 09-08 14:17 ?5次下載
    最全SPARK<b class='flag-5'>內(nèi)存</b><b class='flag-5'>管理機(jī)制</b>

    深入理解C指針(C/C++程序員進(jìn)階必備,透徹理解指針與內(nèi)存管理)pdf

    深入理解C指針
    發(fā)表于 03-21 09:42 ?120次下載

    嵌入式系統(tǒng)內(nèi)存管理機(jī)制詳解

    操作系統(tǒng)的內(nèi)存管理功能用于向操作系統(tǒng)提供一致的地址映射功能和內(nèi)存頁(yè)面的申請(qǐng)、釋放操作。在嵌入式實(shí)時(shí)系統(tǒng)中,內(nèi)存管理根據(jù)不同的系統(tǒng),有不同的策
    發(fā)表于 11-18 09:41 ?4699次閱讀

    淺析物理內(nèi)存與虛擬內(nèi)存的關(guān)系及其管理機(jī)制

    本文主要介紹內(nèi)存管理機(jī)制:物理內(nèi)存與虛擬內(nèi)存的關(guān)系,Linux內(nèi)存管理機(jī)制,Python
    的頭像 發(fā)表于 04-12 09:55 ?5900次閱讀
    淺析物理<b class='flag-5'>內(nèi)存</b>與虛擬<b class='flag-5'>內(nèi)存</b>的關(guān)系及其<b class='flag-5'>管理機(jī)制</b>

    xenomai系統(tǒng)中的xnheap管理機(jī)制

    本文分析的enomai系統(tǒng)中的內(nèi)存池(xnheap)管理機(jī)制。
    的頭像 發(fā)表于 05-25 10:15 ?2017次閱讀

    java內(nèi)存溢出排查方法

    過(guò)程中常見(jiàn)的問(wèn)題之一,可能導(dǎo)致應(yīng)用程序崩潰、性能下降甚至系統(tǒng)崩潰。在本文中,將詳細(xì)介紹如何排查和解決Java內(nèi)存溢出問(wèn)題。 一、什么是Java內(nèi)存
    的頭像 發(fā)表于 11-23 14:46 ?3797次閱讀
    主站蜘蛛池模板: 特级中国aaa毛片 | 91拍拍在线观看 | 轻点灬大ji巴太粗太长了爽文 | 国产欧美在线一区二区三区 | 天天射天天操天天色 | 免费h网站在线观看 | 看免费黄色大片 | 韩国朴银狐诱感在线观看 | 成在线人永久免费播放视频 | 国产偷啪视频一区 | 午夜黄色福利视频 | 九九热精品视频 | 91寡妇天天综合久久影院 | 成人a在线观看 | 美女三级黄 | 亚欧成人中文字幕一区 | 日本亚洲天堂网 | 看天堂 | 天天摸天天做天天爽天天弄 | 夜夜骑狠狠干 | 亚洲特级毛片 | 天堂8在线天堂资源在线 | 色色就色色| 天天插天天狠天天透 | 午夜色大片 | 五月婷婷激情视频 | 欧美性生活网址 | 国产福利在线免费 | 成人黄色在线 | 亚洲综合黄色 | 久久男女 | 白嫩美女一级高清毛片免费看 | 国产亚洲网站 | 黄 色 片 在 线 看 | 唐人社电亚洲一区二区三区 | 97人人在线 | 国产农村乱色xxxx | xxx亚洲日本| 欧美区亚洲区 | 久热福利 | 无遮挡很爽很污很黄的网站w |