一、JVM常見垃圾收集算法

眾所周知,在Java中內(nèi)存的分配和回收都是由java虛擬機(JVM)操作的,我們并不需要像C/C++那樣需要手動分配和釋放內(nèi)存,也正是因為有了JVM,才能使跨平臺成為了可能。說道垃圾回收,我們先要知道在java中內(nèi)存有哪些部分和作用。

一、java內(nèi)存組成

在JVM中,內(nèi)存主要分為一下幾個部分:程序計數(shù)器(PC)、方法棧、本地方法棧、堆、方法區(qū)

1、程序計數(shù)器:

操作系統(tǒng)在線程切換和恢復的時候,必須要記錄任務執(zhí)行的位置,這樣,當任務恢復的時候,才知道該從哪里繼續(xù)執(zhí)行,程序計數(shù)器就是記錄程序執(zhí)行的位置的,可以簡單理解成字節(jié)碼的行號指示器。
因為每個線程都是獨立執(zhí)行的,所以每個線程都有一個程序計數(shù)器,意味著,程序計數(shù)器是線程私有的。
對于java方法來說,程序計數(shù)器記錄的是字節(jié)碼的指令地址,對于native方法來說,它的值為空。
程序計數(shù)器是唯一一個不會發(fā)生OOM(out of memory)的地方。

2、方法棧

方法棧也叫作虛擬機棧,對每個即將執(zhí)行的方法,都會為其創(chuàng)建一個棧幀,對于java方法從開始執(zhí)行,到執(zhí)行結束,就是一個入棧到出棧的過程。
方法棧包含局部變量表,操作數(shù)棧,方法退出地址等。
方法棧是線程私有的。
當內(nèi)存不夠創(chuàng)建新的棧幀的時候,會拋出OutOfMemoryError;當方法棧調(diào)用深度超過棧的最大深度時,就會出現(xiàn)StackOverflowError,可以使用-Xss設置棧的大小。

3、本地方法棧

本地方法棧和方法棧很類似,但是只是執(zhí)行native方法時才會使用,JVM規(guī)范并沒有對本地方法棧的實現(xiàn)有強制性要求,所以會根據(jù)每個JVM的不同有不同的實現(xiàn)。本地方法棧也是線程私有的,同樣會拋出OutOfMemoryError和StackOverflowError。

4、方法區(qū)

JVM在java類在加載后,會將class文件代表的靜態(tài)存儲結構轉(zhuǎn)換為方法區(qū)的可運行結構,并將該結構存儲在方法區(qū)中。主要存儲的是類信息,常量池,類變量和JIT編譯后的數(shù)據(jù)。常量池主要包括字面量和符號引用。字面量比較接近java中常量的概念,比如字符串,final修飾的數(shù)據(jù)等,而符號引用只要是類和接口的全限定名,字段的名稱和描述符,方法的名稱和描述符。
方法區(qū)中的數(shù)據(jù)是共享的,對所有線程可見。
常量池在運行時也可以改變,比如調(diào)用字符串的intern()方法。
當內(nèi)存不夠分配新的常量空間的時候,也會拋出OutOfMemoryError。

5、堆

堆主要用來存儲新對象和數(shù)組,前面4部分的內(nèi)存都是由JVM進行管理和控制,對于開發(fā)人員來說,堆是可操作性最高的部分,當創(chuàng)建新的對象時,JVM會根據(jù)類信息在堆中分配一塊內(nèi)存給新的對象,當內(nèi)存不夠時,也會拋出OutOfMemoryError,同時,這部分區(qū)域也是垃圾收集器重要的收集對象。

二、垃圾收集算法

分配內(nèi)存很好理解,只要在需要分配內(nèi)存的地方申請相應的地址空間就可以,但是,內(nèi)存回收就沒這么簡單了,需要在程序運行過程中判斷對象是否還有用,對于沒有用的對象,需要對其占用的空間進行回收。這里我們簡單介紹下各種垃圾回收算法及其優(yōu)劣。

1、引用計數(shù)法

引用計數(shù)法就是記錄對象的引用,用來判斷對象是否還有用。對于一個對象,當有別的地方訪問它時,引用計數(shù)器數(shù)值+1,當不再引用它時,計數(shù)器-1,當對象的引用計數(shù)器數(shù)值為0的時候,說明該對象不再被使用,可以被回收。引用計數(shù)法實現(xiàn)很簡單,只需要對每個對象增加一個計數(shù)器即可,但是,對于對象間的循環(huán)引用就無能為力了。

2、標記清除算法

為了解決對象間循環(huán)引用的問題,有了標記-清除算法,就像它的名字一樣,等需要開始垃圾回收的時候,從GC Root開始,GC線程會把引用不到的對象標記出來(循環(huán)引用的對象自然就會被標記出來了),然后就把標記過的對象清除,這樣就可以釋放無用對象所占用的內(nèi)存了。但是,這里面有一個很嚴重問題-內(nèi)存碎片化嚴重,這樣會嚴重影響內(nèi)存的利用率。
舉個栗子,現(xiàn)在創(chuàng)建一個需要100MB內(nèi)存的對象,但是內(nèi)存只剩20MB,不夠,所以觸發(fā)了GC并且清理了120個對象騰出100MB的內(nèi)存,按說現(xiàn)在120MB的內(nèi)存已經(jīng)夠了,但多數(shù)情況下還是會拋出OOM異常,因為這些對象不是連續(xù)存儲的,所以清理出來的內(nèi)存也不是連續(xù)的,由于不存在連續(xù)的100MB的內(nèi)存,所以會拋異常。

3、復制算法

復制算法為了解決標記清除算法內(nèi)存碎片化的問題。復制算法主要工作流程為:
將內(nèi)存按照一定比例分為兩部分(通常為五五分),對象在只其中的一部分創(chuàng)建
在觸發(fā)GC后,從GC Root開始將能夠引用到的對象(有效對象)依次復制到另外一部分
完成所有有效對象的復制后,清除這部分內(nèi)存
下次GC又從另外一部分內(nèi)存復制到當前部分內(nèi)存,清除另一部分內(nèi)存

這樣,內(nèi)存碎片化的問題就解決了,但是,你會發(fā)現(xiàn),同一時間其實只有一部分內(nèi)存在使用,另外一部分都是在空閑的,這樣導致內(nèi)存利用率很低(五五分情況下內(nèi)存利用率最多到50%)

4、標記整理算法

標記整理算法是為了解決標記清除算法內(nèi)存碎片化和復制算法內(nèi)存利用率低的問題,它其實也是這兩種算法的結合。工作流程如下:
觸發(fā)GC后,從GC Root開始將有效對象標記出來
將有效對象依次移動到可用內(nèi)存開始處
將剩余部分內(nèi)存清

目前看來,標記整理算法解決了前面幾種方法的弊端,也沒有引入比較嚴重的新的問題,那么是不是就沒有任何問題,成為垃圾收集的銀彈了呢?答案是:當然不是。原因在于,前面所說的垃圾回收的過程中,除了GC線程外,jvm會停止所有java程序的運行,在jvm領域也稱為stop the world,這樣做的好處和壞處都顯而易見,好處就是減少了GC的復雜性,壞處就是java應用都被暫時停止,直到GC結束。在GC算法發(fā)展的過程中,細心的人會發(fā)現(xiàn),有些對象的生存周期很長,甚至和整個應用的生命周期相同,比如方法區(qū)中的類的字節(jié)碼所對應的結構,以及堆中代表類的Class對象;有的對象生命周期很短,比如方法中申明的變量所引用的對象,在方法結束后即失效。這種根據(jù)生命周期長短劃分對象,接近應用的生命周期的叫做永久代,生命周期長的叫做老年代,生命周期短的叫做新生代。

5、分代算法

其實分代算法不是一個具體的垃圾回收算法,它只是根據(jù)對象生命周期的長短,選擇不同的回收算法。比如說,復制算法,如果大多數(shù)都是新生代對象,每次復制的對象會很少,那么效率就會比較高;相反,如果大多數(shù)對象屬于老年代或者永久代,那么每次需要復制的對象就會特別多,效率就會很低。比如標記復制或者標記整理算法,如果是老年代居多,那么每次需要復制或者整理的對象就比較少,相反,如果是新生代居多,需要復制或者整理的內(nèi)存就會很多,效率自然就低很多。
所以分代算法主要就是根據(jù)生命周期的長短選擇合適的算法。一般來說,新生代居多合適用復制算法,老年代適合標記復制算法,永久代適合標記整理算法。
所以說在實際應用過程中,應該根據(jù)應用的特點選擇合適的垃圾收集算法。

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,431評論 6 544
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,637評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 178,555評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,900評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,629評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,976評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,976評論 3 448
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,139評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,686評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 41,411評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,641評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,129評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,820評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,233評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,567評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,362評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,604評論 2 380

推薦閱讀更多精彩內(nèi)容