面試準備之JVM的組成、垃圾回收機制(轉載)

原博客鏈接:https://www.cnblogs.com/wabi87547568/p/5282892.html

1.JVM的組成

JVM定義了控制Java代碼解釋執(zhí)行和具體實現(xiàn)的五種規(guī)格斋扰,因此把JVM分成了6個部分:JVM解釋器、指令系統(tǒng)、寄存器杂靶、棧、存儲區(qū)和碎片回收區(qū)酱鸭。

◆JVM解釋器:即這個虛擬機處理字段碼的CPU吗垮。

◆JVM指令系統(tǒng):該系統(tǒng)與計算機很相似,一條指令由操作碼和操作數(shù)兩部分組成凹髓。操作碼為8位二進制數(shù)烁登,主要是為了說明一條指令的功能,操作數(shù)可以根據(jù)需要而定蔚舀,JVM最多有256種不同的操作指令饵沧。目前已使用了160多種操作碼锨络。

◆寄存器:JVM有自己的虛擬寄存器,這樣就可以快速地與JVM的解釋器進行數(shù)據(jù)交換狼牺。為了功能的需要羡儿,JVM設置了4個常用的32位寄存器:pc(程序計數(shù)器)、optop(操作數(shù)棧頂指針)是钥、frame(當前執(zhí)行環(huán)境指針)和vars(指向當前執(zhí)行環(huán)境中第一個局部變量的指針)失受。

◆JVM棧:指令執(zhí)行時數(shù)據(jù)和信息存儲的場所和控制中心,它提供給JVM解釋器運算所需要的信息咏瑟。當JVM得到一個Java字節(jié)碼應用程序后拂到,便為該代碼中一個類的每一個方法創(chuàng)建一個棧框架码泞,以保存該方法的狀態(tài)信息兄旬。每個棧框架包括以下三類信息:局部變量余寥、執(zhí)行環(huán)境领铐、操作數(shù)棧。

局部變量用于存儲一個類的方法中所用到的局部變量宋舷。vars寄存器指向該變量表中的第一個局部變量绪撵。

執(zhí)行環(huán)境用于保存解釋器對Java字節(jié)碼進行解釋過程中所需的信息。它們是:上次調用的方法祝蝠、局部變量指針和操作數(shù)棧的棧頂和棧底指針音诈。執(zhí)行環(huán)境是一個執(zhí)行一個方法的控制中心。例如:如果解釋器要執(zhí)行iadd(整數(shù)加法)绎狭,首先要從frame寄存器中找到當前執(zhí)行環(huán)境细溅,而后便從執(zhí)行環(huán)境中找到操作數(shù)棧,從棧頂彈出兩個整數(shù)進行加法運算儡嘶,最后將結果壓入棧頂喇聊。

操作數(shù)棧用于存儲運算所需操作數(shù)及運算的結果。

◆存儲區(qū):JVM有兩類存儲區(qū):常量緩沖池和方法區(qū)蹦狂。常量緩沖池用于存儲類名稱誓篱、方法和字段名稱以及串常量。方法區(qū)則用于存儲Java方法的字節(jié)碼凯楔。

◆碎片回收區(qū):JVM碎片回收是指將使用過的Java類的具體實例從內存進行回收窜骄,這就使得開發(fā)人員免去了自己編程控制內存的麻煩和危險。隨著JVM的不斷升級啼辣,其碎片回收的技術和算法也更加合理啊研。JVM 1.4.1版后產(chǎn)生了一種叫分代收集技術,簡單來說就是利用對象在程序中生存的時間劃分成代,以此為標準進行碎片回收党远。

2.JAVA的垃圾回收機制 GC通過確定對象是否被活動對象引用來確定是否收集該對象削解。

2.1 觸發(fā)GC(Garbage Collector)的條件

1)GC在優(yōu)先級最低的線程中運行,一般在應用程序空閑即沒有應用線程在運行時被調用沟娱。但下面的條件例外氛驮。

2)Java堆內存不足時,GC會被調用济似。當應用線程在運行矫废,并在運行過程中創(chuàng)建新對象,若這時內存空間不足砰蠢,JVM就會強制調用GC線程蓖扑。若GC一次之后仍不能滿足內存分配,JVM會再進行兩次GC台舱,若仍無法滿足要求律杠,則JVM將報“out of memory”的錯誤,Java應用將停止竞惋。

2.2 兩個重要方法

2.2.1 System.gc()方法

使用System.gc()可以不管JVM使用的是哪一種垃圾回收的算法柜去,都可以請求Java的垃圾回收。在命令行中有一個參數(shù)-verbosegc可以查看Java使用的堆內存的情況拆宛,它的格式如下:java -verbosegc classfile 由于這種方法會影響系統(tǒng)性能嗓奢,不推薦使用,所以不詳訴浑厚。

2.2.2 finalize()方法

在JVM垃圾回收器收集一個對象之前股耽,一般要求程序調用適當?shù)姆椒ㄡ尫刨Y源,但在沒有明確釋放資源的情況下瞻颂,Java提供了缺省機制來終止該對象心釋放資源豺谈,這個方法就是finalize()郑象。它的原型為:protected void finalize() throws Throwable 在finalize()方法返回之后贡这,對象消失,垃圾收集開始執(zhí)行厂榛。原型中的throws Throwable表示它可以拋出任何類型的異常盖矫。

之所以要使用finalize(),是存在著垃圾回收器不能處理的特殊情況击奶。例如:1)由于在分配內存的時候可能采用了類似 C語言的做法辈双,而非JAVA的通常new做法。這種情況主要發(fā)生在native method中柜砾,比如native method調用了C/C++方法malloc()函數(shù)系列來分配存儲空間湃望,但是除非調用free()函數(shù),否則這些內存空間將不會得到釋放,那么這個時候就可能造成內存泄漏证芭。但是由于free()方法是在C/C++中的函數(shù)瞳浦,所以finalize()中可以用本地方法來調用它。以釋放這些“特殊”的內存空間废士。2)又或者打開的文件資源叫潦,這些資源不屬于垃圾回收器的回收范圍。

2.3 減少GC開銷的措施

1)不要顯式調用System.gc()官硝。此函數(shù)建議JVM進行主GC,雖然只是建議而非一定,但很多情況下它會觸發(fā)主GC,從而增加主GC的頻率,也即增加了間歇性停頓的次數(shù)矗蕊。大大的影響系統(tǒng)性能。

2)盡量減少臨時對象的使用氢架。臨時對象在跳出函數(shù)調用后,會成為垃圾,少用臨時變量就相當于減少了垃圾的產(chǎn)生,從而延長了出現(xiàn)上述第二個觸發(fā)條件出現(xiàn)的時間,減少了主GC的機會傻咖。

3)對象不用時最好顯式置為Null。一般而言,為Null的對象都會被作為垃圾處理,所以將不用的對象顯式地設為Null,有利于GC收集器判定垃圾,從而提高了GC的效率岖研。

4)盡量使用StringBuffer,而不用String來累加字符串没龙。由于String是固定長的字符串對象,累加String對象時,并非在一個String對象中擴增,而是重新創(chuàng)建新的String對象,如Str5=Str1+Str2+Str3+Str4,這條語句執(zhí)行過程中會產(chǎn)生多個垃圾對象,因為對次作“+”操作時都必須創(chuàng)建新的String對象,但這些過渡對象對系統(tǒng)來說是沒有實際意義的,只會增加更多的垃圾。避免這種情況可以改用StringBuffer來累加字符串,因StringBuffer是可變長的,它在原有基礎上進行擴增,不會產(chǎn)生中間對象缎玫。

5)能用基本類型如Int,Long,就不用Integer,Long對象硬纤。基本類型變量占用的內存資源比相應對象占用的少得多,如果沒有必要,最好使用基本變量赃磨。

6)盡量少用靜態(tài)對象變量筝家。靜態(tài)變量屬于全局變量,不會被GC回收,它們會一直占用內存。

7)分散對象創(chuàng)建或刪除的時間邻辉。集中在短時間內大量創(chuàng)建新對象,特別是大對象,會導致突然需要大量內存,JVM在面臨這種情況時,只能進行主GC,以回收內存或整合內存碎片,從而增加主GC的頻率溪王。集中刪除對象,道理也是一樣的。它使得突然出現(xiàn)了大量的垃圾對象,空閑空間必然減少,從而大大增加了下一次創(chuàng)建新對象時強制主GC的機會值骇。

2.4 對象在JVM堆區(qū)的狀態(tài)

1)可觸及狀態(tài):程序中還有變量引用莹菱,那么此對象為可觸及狀態(tài)。

2)可復活狀態(tài):當程序中已經(jīng)沒有變量引用這個對象吱瘩,那么此對象由可觸及狀態(tài)轉為可復活狀態(tài)监徘。CG線程將在一定的時間準備調用此對象的finalize方法(finalize方法繼承或重寫子Object),finalize方法內的代碼有可能將對象轉為可觸及狀態(tài)胁艰,否則對象轉化為不可觸及狀態(tài)涩澡。

3)不可觸及狀態(tài):只有當對象處于不可觸及狀態(tài)時,GC線程才能回收此對象的內存票摇。

[圖片上傳失敗...(image-125b4-1539142222224)]

Jvm堆區(qū)對象狀態(tài)轉換圖

2.5 常用垃圾收集器

1) 標記-清除收集器 Mark-Sweep

2) 復制收集器 Copying

3) 標記-壓縮收集器 Mark-Compact

4) 分代收集器   Generational

2.6 垃圾收集算法介紹

2.6.1 tracing算法

基于tracing算法的垃圾收集也稱為標記和清除(mark-and-sweep)垃圾收集器.

這是最基礎的垃圾回收算法拘鞋,之所以說它是最基礎的是因為它最容易實現(xiàn),思想也是最簡單的矢门。標記-清除算法分為兩個階段:標記階段和清除階段盆色。標記階段的任務是標記出所有需要被回收的對象灰蛙,清除階段就是回收被標記的對象所占用的空間。具體過程如下圖所示:

image

從圖中可以很容易看出標記-清除算法實現(xiàn)起來比較容易隔躲,但是有一個比較嚴重的問題就是容易產(chǎn)生內存碎片缕允,碎片太多可能會導致后續(xù)過程中需要為大對象分配空間時無法找到足夠的空間而提前觸發(fā)新的一次垃圾收集動作。

2.6.2 Copying算法

為了解決Mark-Sweep算法的缺陷蹭越,Copying算法就被提了出來障本。它將可用內存按容量劃分為大小相等的兩塊,每次只使用其中的一塊响鹃。當這一塊的內存用完了驾霜,就將還存活著的對象復制到另外一塊上面买置,然后再把已使用的內存空間一次清理掉粪糙,這樣一來就不容易出現(xiàn)內存碎片的問題。具體過程如下圖所示:

image

這種算法雖然實現(xiàn)簡單忿项,運行高效且不容易產(chǎn)生內存碎片,但是卻對內存空間的使用做出了高昂的代價,因為能夠使用的內存縮減到原來的一半惨好。很顯然日川,Copying算法的效率跟存活對象的數(shù)目多少有很大的關系龄句,如果存活對象很多,那么Copying算法的效率將會大大降低繁调。

2.6.3 compacting算法

為了解決Copying算法的缺陷奕翔,充分利用內存空間派继,提出了Mark-Compact算法绅络。該算法標記階段和Mark-Sweep一樣恩急,但是在完成標記之后匾荆,它不是直接清理可回收對象简卧,而是將存活對象都向一端移動铜涉,然后清理掉端邊界以外的內存盖彭。具體過程如下圖所示:

image

2.6.4 Generation算法

分代收集算法是目前大部分JVM的垃圾收集器采用的算法幻林。它的核心思想是根據(jù)對象存活的生命周期將內存劃分為若干個不同的區(qū)域沪饺。一般情況下將堆區(qū)劃分為老年代(Tenured Generation)和新生代(Young Generation)肝谭,老年代的特點是每次垃圾收集時只有少量對象需要被回收鼠次,而新生代的特點是每次垃圾回收時都有大量的對象需要被回收,那么就可以根據(jù)不同代的特點采取最適合的收集算法赦役。

目前大部分垃圾收集器對于新生代都采取Copying算法赢赊,因為新生代中每次垃圾回收都要回收大部分對象叭披,也就是說需要復制的操作次數(shù)較少锋边,但是實際中并不是按照1:1的比例來劃分新生代的空間的皱坛,一般來說是將新生代劃分為一塊較大的Eden空間和兩塊較小的Survivor空間,每次使用Eden空間和其中的一塊Survivor空間豆巨,當進行回收時剩辟,將Eden和Survivor中還存活的對象復制到另一塊Survivor空間中,然后清理掉Eden和剛才使用過的Survivor空間往扔。

而由于老年代的特點是每次回收都只回收少量對象贩猎,一般使用的是Mark-Compact算法。

image

新年代:新創(chuàng)建的對象都存放在這里萍膛。因為大多數(shù)對象很快變得不可達吭服,所以大多數(shù)對象在年輕代中創(chuàng)建,然后消失蝗罗。當對象從這塊內存區(qū)域消失時艇棕,我們說發(fā)生了一次“minor GC”。

老年代:沒有變得不可達串塑,存活下來的年輕代對象被復制到這里沼琉。這塊內存區(qū)域一般大于年輕代。因為它更大的規(guī)模桩匪,GC發(fā)生的次數(shù)比在年輕代的少打瘪。對象從老年代消失時,我們說“major GC”(或“full GC”)發(fā)生了傻昙。

上圖中的永久代(permanent generation)也稱為“方法區(qū)(method area)”闺骚,他存儲class對象和字符串常量。所以這塊內存區(qū)域絕對不是永久的存放從老年代存活下來的對象的妆档。在這塊內存中有可能發(fā)生垃圾回收僻爽。發(fā)生在這里垃圾回收也被稱為major GC。

對于分代算法过吻,我推薦一篇博客給大家:http://blog.jobbole.com/80499/

推薦閱讀:LeakCanary 內存泄露監(jiān)測原理研究 进泼, 話說ReferenceQueue

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市纤虽,隨后出現(xiàn)的幾起案子乳绕,更是在濱河造成了極大的恐慌,老刑警劉巖逼纸,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件洋措,死亡現(xiàn)場離奇詭異,居然都是意外死亡杰刽,警方通過查閱死者的電腦和手機菠发,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進店門王滤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人滓鸠,你說我怎么就攤上這事雁乡。” “怎么了糜俗?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵踱稍,是天一觀的道長。 經(jīng)常有香客問我悠抹,道長珠月,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任楔敌,我火速辦了婚禮啤挎,結果婚禮上,老公的妹妹穿的比我還像新娘卵凑。我一直安慰自己庆聘,他們只是感情好,可當我...
    茶點故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布氛谜。 她就那樣靜靜地躺著掏觉,像睡著了一般。 火紅的嫁衣襯著肌膚如雪值漫。 梳的紋絲不亂的頭發(fā)上澳腹,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天,我揣著相機與錄音杨何,去河邊找鬼酱塔。 笑死,一個胖子當著我的面吹牛危虱,可吹牛的內容都是我干的羊娃。 我是一名探鬼主播,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼埃跷,長吁一口氣:“原來是場噩夢啊……” “哼蕊玷!你這毒婦竟也來了?” 一聲冷哼從身側響起弥雹,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤垃帅,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后剪勿,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體贸诚,經(jīng)...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了酱固。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片械念。...
    茶點故事閱讀 38,599評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖运悲,靈堂內的尸體忽然破棺而出龄减,到底是詐尸還是另有隱情,我是刑警寧澤扇苞,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布欺殿,位于F島的核電站寄纵,受9級特大地震影響鳖敷,放射性物質發(fā)生泄漏。R本人自食惡果不足惜程拭,卻給世界環(huán)境...
    茶點故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一定踱、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧恃鞋,春花似錦崖媚、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至水由,卻和暖如春荠呐,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背砂客。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工泥张, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人鞠值。 一個月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓媚创,卻偏偏與公主長得像,于是被迫代替她去往敵國和親彤恶。 傳聞我的和親對象是個殘疾皇子钞钙,可洞房花燭夜當晚...
    茶點故事閱讀 43,465評論 2 348

推薦閱讀更多精彩內容