- 資訊首頁(yè) > 開(kāi)發(fā)技術(shù) > 編程語(yǔ)言 >
- Java基礎之垃圾回收機制詳解
進(jìn)行內存管理
C語(yǔ)言中的內存,申請內存之后需要手動(dòng)釋放;一旦忘記釋放,就會(huì )發(fā)生內存泄漏!
而Java語(yǔ)言中,申請內存后會(huì )由GC來(lái)釋放內存空間,無(wú)需手動(dòng)釋放
GC雖然代替了手動(dòng)釋放的操作,但是它也有局限性:
(1)堆:主要回收堆中的內存
(2)方法區:需要回收
(3)棧(包括本地方法棧和JVM虛擬機棧):不需要回收,棧上的內存什么時(shí)候釋放是明確的(線(xiàn)程結束,棧上的內存也就被釋放了;對應的某個(gè)棧幀銷(xiāo)毀[某個(gè)方法執行完畢],也會(huì )導致對應的局部變量被釋放)
(4)程序計數器:不需要被回收
GC回收內存的基本單位:對象
GC回收對象的基本思路
(1)標記:判斷當前對象的生死,對象不再被使用為死,則需要回收,反之不需要被回收;
標記的方法:
記錄當前這個(gè)對象是否有引用指向,有則引用計數加1,如果當前這個(gè)對象的引用指向了其他新的對象,則引用計數減1,當引用計數為0的時(shí)候,我們認為這個(gè)對象需要被回收!
缺點(diǎn):無(wú)法解決循環(huán)引用問(wèn)題
下面用一段偽代碼來(lái)演示一下循環(huán)引用問(wèn)題:
class Test{ Test t = null; } Test a = new Test(); Test b = new Test(); a.t = b; b.t = a; a = null; b = null;
我們發(fā)現,在上述代碼中已經(jīng)沒(méi)有辦法使用對象a和對象b了,但是它們的引用計數不為1.想使用對象a,就得找到對象a的引用,但是對象a的引用又在對象b當中。想使用對象b,就得找到對象b 的引用,但是對象b的引用又在對象a當中。
代碼中的對象具有一定的關(guān)聯(lián)關(guān)系,這樣錯綜復雜的關(guān)系,構成了一個(gè)"有向圖"??蛇_性分析也就是遍歷這個(gè)對象關(guān)系的“有向圖”。如果某個(gè)對象可以被遍歷到,那么它就是可達的(非垃圾),那么就是不可達的(是垃圾)
那么可達性分析從哪里開(kāi)始呢?
a)針對每個(gè)線(xiàn)程的每個(gè)棧幀的局部變量表(線(xiàn)程有很多,每個(gè)線(xiàn)程棧幀也有很多,每個(gè)棧幀也會(huì )有很多個(gè)變量);
b)常量池中引用的對象;
c)方法區中靜態(tài)變量引用的對象;
因為遍歷的起點(diǎn)不止一個(gè),而是很多個(gè)起點(diǎn),因此把這些起點(diǎn)也稱(chēng)之為GCRoot
a)該類(lèi)的所有實(shí)例已經(jīng)被回收;
b)加載類(lèi)的ClassLoader也已經(jīng)被回收了;
c)該類(lèi)對象沒(méi)有在代碼中使用了
同時(shí)具備以上三個(gè)條件,就認為該類(lèi)對象是可以被回收的
回收的方法:
通過(guò)上面的圖,我們可以發(fā)現,兩個(gè)空閑區被其他的對象分隔開(kāi)了。一旦需要一個(gè)比較大的空間,就會(huì )申請失敗。
標記-清除法的優(yōu)缺點(diǎn):
優(yōu)點(diǎn):簡(jiǎn)單高效
缺點(diǎn):會(huì )出現內存碎片
優(yōu)點(diǎn):解決了內存碎片問(wèn)題,保證回收之后不會(huì )存在碎片(回收后使用的對象之間是連續的,空余內存之間也是連續的)
缺點(diǎn):需要一塊額外的空間,如果生存的對象較多就比較難低效
優(yōu)點(diǎn):沒(méi)有內存碎片問(wèn)題,也不需要額外的空間
缺點(diǎn):類(lèi)似于順序表的刪除操作,效率不是很高
按照對象的年齡,將堆內存分為:新生代(伊甸區和生存區)、老年代
對象的年齡不是直接使用時(shí)間來(lái)記錄,而是使用對象活過(guò)GC輪次來(lái)記錄(GC是按照一定周期來(lái)運行)
一個(gè)對象的一生:
(1)對象誕生于新生代的伊甸區。新產(chǎn)生的對象的內存就是新生代中的內存
(2)第一輪GC掃描伊甸區之后,就會(huì )把大量的對象回收掉。少數沒(méi)有被回收的對象,就會(huì )通過(guò)標記-復制算法進(jìn)入到生存區
(3)少數進(jìn)入生存區的對象,再次被GC掃描(對這些對象進(jìn)行可達性分析)。如果發(fā)現該對象已經(jīng)不可達,也就被銷(xiāo)毀了。沒(méi)有被銷(xiāo)毀的對象,再次通過(guò)標記-復制算法,把它拷貝到另一個(gè)生存區。
(4)對象在兩個(gè)生存區中經(jīng)過(guò)若干次拷貝,如果還沒(méi)有被回收,那么就說(shuō)明這些個(gè)對象存活時(shí)間比較久,就拷貝到老年代
(5)老年代的對象也是要經(jīng)過(guò)GC掃描的。由于老年代的對象生存時(shí)間比較長(cháng)。因此掃描周期要比新生代的周期要長(cháng)
相關(guān)術(shù)語(yǔ):
垃圾回收器做的兩件事情:標記(可達性分析)+回收(標記清除,標記復制,標記整理)
采用復制算法,單線(xiàn)程進(jìn)行標記和回收
采用復制算法,多線(xiàn)程進(jìn)行標記和回收
設計初衷是為了縮短STW時(shí)間,以犧牲吞吐量和新生代空間作為代價(jià)。
相當于承諾用戶(hù),在一定時(shí)間內就會(huì )完成一次GC。
使用多線(xiàn)程完成標記整理,效率更高,消耗的CPU資源更多
a)初始標記【STW】
只是把和GCRoot相關(guān)的對象標記出來(lái),涉及STW
b)并發(fā)標記
執行整個(gè)標記遍歷的過(guò)程(從GCRoot開(kāi)始,把能訪(fǎng)問(wèn)的對象都遍歷)
不需要暫停用戶(hù)線(xiàn)程
消耗的時(shí)間相對比較久,但是可以和用戶(hù)線(xiàn)程并發(fā)
注意:當進(jìn)行并發(fā)標記的時(shí)候,當用戶(hù)線(xiàn)程也在執行,可能導致某個(gè)對象,剛剛標記的時(shí)候不是垃圾,代碼執行后,就成了垃圾
c)重新標記(CMS remark)【STW】
修正誤差
d)并發(fā)清除
多線(xiàn)程的方式將剛剛的垃圾對象都清除釋放掉,可以和應用程序并發(fā)執行
優(yōu)點(diǎn):能夠讓STW時(shí)間盡量短
缺點(diǎn):有內存碎片; GC操作和應用程序并發(fā)進(jìn)行,消耗CPU資源多;
既可以回收新生代,也可以回收老年代
每個(gè)矩形稱(chēng)為一個(gè)region
E表示伊甸區
S表示生存區
T表示老年代
H表示存放大對象的區域
以region為單位進(jìn)行回收,回收粒度更精細
針對新生區的region同樣適用復制算法
針對老年代的回收類(lèi)似于CMS
a)初始標記【STW】:只去找和GRoot直接相連的對象
b)并發(fā)標記:和應用程序并發(fā)執行,進(jìn)行可達性分析,遍歷所有對象。如果發(fā)現某個(gè)老年代region中已經(jīng)沒(méi)有存活對象,就直接回收
c)最終標記:修正第二步產(chǎn)生的誤差
d)篩選回收:挑選出對象存活率低的region進(jìn)行回收
到此這篇關(guān)于Java基礎之垃圾回收機制詳解的文章就介紹到這了,更多相關(guān)Java垃圾回收機制內容請搜索腳本之家以前的文章或繼續瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng )、來(lái)自本網(wǎng)站內容采集于網(wǎng)絡(luò )互聯(lián)網(wǎng)轉載等其它媒體和分享為主,內容觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如侵犯了原作者的版權,請告知一經(jīng)查實(shí),將立刻刪除涉嫌侵權內容,聯(lián)系我們QQ:712375056,同時(shí)歡迎投稿傳遞力量。
Copyright ? 2009-2022 56dr.com. All Rights Reserved. 特網(wǎng)科技 特網(wǎng)云 版權所有 特網(wǎng)科技 粵ICP備16109289號
域名注冊服務(wù)機構:阿里云計算有限公司(萬(wàn)網(wǎng)) 域名服務(wù)機構:煙臺帝思普網(wǎng)絡(luò )科技有限公司(DNSPod) CDN服務(wù):阿里云計算有限公司 百度云 中國互聯(lián)網(wǎng)舉報中心 增值電信業(yè)務(wù)經(jīng)營(yíng)許可證B2
建議您使用Chrome、Firefox、Edge、IE10及以上版本和360等主流瀏覽器瀏覽本網(wǎng)站