JVM垃圾回收
內(nèi)存結(jié)構(gòu)
要想理解jvm的垃圾回收機(jī)制晰奖,必須先知道java虛擬機(jī)的內(nèi)存結(jié)構(gòu)。
程序計數(shù)器
程序計數(shù)器是一塊較小的內(nèi)存空間今布,你可以把它看成是當(dāng)前線程所執(zhí)行字節(jié)碼文件的行號指示器褒链。它存在的主要意義就是,在切換回當(dāng)前線程時可以恢復(fù)到切換之前的狀態(tài)姻僧。它也是java虛擬機(jī)中唯一沒有規(guī)定任何OutOfMemoryError情況的區(qū)域。java虛擬機(jī)棧
這個區(qū)域是線程私有的蒲牧,主要用來存放基礎(chǔ)類型如int撇贺,對象的引用(注意不是對象本身),局部變量冰抢。
在Java虛擬機(jī)規(guī)范中松嘶,對這個區(qū)域 規(guī)定了 兩種 異常 狀況: 如果 線程 請求 的 棧 深度 大于 虛擬 機(jī) 所 允許 的 深度, 將 拋出 StackOverflowError 異常挎扰; 如果 虛擬 機(jī) 棧 可以 動態(tài) 擴(kuò)展翠订, 如果 擴(kuò)展 時 無法 申請 到 足夠 的 內(nèi)存巢音, 就會 拋出 OutOfMemoryError 異常。本地方法棧
和虛擬機(jī)棧一樣尽超,只不過主要針對native方法官撼。java堆
java堆是java虛擬機(jī)管理內(nèi)存中最大的一塊,它的目的是管理對象內(nèi)存的分配橙弱,所以垃圾回收主要集中在堆中歧寺。它是線程共享的。方法區(qū)
方法區(qū)和堆一樣棘脐,也是各個線程共享的斜筐。它主要存儲類信息、常量蛀缝、以及靜態(tài)變量顷链、及時編譯的代碼。
程序計數(shù)器屈梁、虛擬機(jī)棧嗤练、本地方法棧這幾塊內(nèi)存區(qū)域,隨線程而生在讶,隨線程而滅煞抬,因此這幾塊區(qū)域不需要內(nèi)存回收并不需要擔(dān)心。
而堆和方法區(qū)中的對象都是運(yùn)行時創(chuàng)建的构哺,對象創(chuàng)建和回收都需要進(jìn)行管理革答。
如何識別垃圾對象
要想進(jìn)行垃圾回收,識別出“垃圾”很重要曙强。在jvm中使用的是可達(dá)性分析算法進(jìn)行識別残拐。它主要是通過一個對象是否在gcRoots對象的引用鏈中來確定對象是否需要回收的。而GcRoot主要包括:棧幀中的變量(方法中的局部變量)碟嘴、方法區(qū)中的常量溪食、方法區(qū)中的靜態(tài)變量、jni中引用的對象娜扇。
垃圾回收算法
識別出內(nèi)存中無用對象以后错沃,就需要進(jìn)行清理,主要的垃圾回收算法主要有三種雀瓢。
標(biāo)記-清理算法
這種算法主要是先標(biāo)記出無用對象枢析,在一次性清理掉他們。這種算法有兩大弊端致燥,首先效率上標(biāo)記和清理都不算高效操作,第二內(nèi)存上排截,這樣會產(chǎn)生大量的不連續(xù)內(nèi)存嫌蚤,空間利用率不高復(fù)制算法
這種算法將內(nèi)存分為兩塊辐益,每次垃圾回收時將有用內(nèi)存移入另一塊內(nèi)存中,然后清空這一側(cè)的內(nèi)存脱吱。這種算法智政,浪費(fèi)了一半的內(nèi)存空間。標(biāo)記-整理算法
這種算法標(biāo)記過程和標(biāo)記清理算法很像箱蝠,但是在清理時會將存活對象都像一段移動续捂,然后直接清理掉端邊界以外的內(nèi)存空間。分代回收算法
該算法宦搬,將內(nèi)存分為年輕代和老年代牙瓢,針對他們不同的特點(diǎn)采用不同回收算法,在年輕代中大部分對象都是朝生夕死间校,因此采用復(fù)制算法矾克,將內(nèi)存分為eden區(qū)和兩塊survivor區(qū),一般按8:1:1的比例分配憔足,內(nèi)存分配主要在eden區(qū)和其中一塊survivor區(qū)中胁附,當(dāng)進(jìn)行垃圾回收時,將存活內(nèi)存移至另一塊survivor區(qū)中滓彰,當(dāng)另一塊survivor區(qū)內(nèi)存不夠時控妻,會臨時存入老年代中。在老年代中的對象都死生命周期很長的揭绑,因此采用標(biāo)記清理或標(biāo)記整理算法進(jìn)行垃圾回收弓候。