日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當前位置:首頁 > 科技  > 軟件

面試官:JVM是如何判定對象已死的?學JVM必會的知識!

來源: 責編: 時間:2023-10-10 18:32:32 399觀看
導讀大家好,我是 BookSea。作為一名Java程序員,我們每天都在程序里不停地去new對象,但是你知道這些被new出來的對象,最后是怎么被回收的嗎?在堆里面存放著Java世界中幾乎所有的對象實例,垃圾收集器在對堆進行回收前,第一件事情就

大家好,我是 BookSea。QYO28資訊網——每日最新資訊28at.com

作為一名Java程序員,我們每天都在程序里不停地去new對象,但是你知道這些被new出來的對象,最后是怎么被回收的嗎?QYO28資訊網——每日最新資訊28at.com

在堆里面存放著Java世界中幾乎所有的對象實例,垃圾收集器在對堆進行回收前,第一件事情就是要確定這些對象之中哪些還「存活」著,哪些已經「死去」(“死去”即不可能再被任何途徑使用的對象)。QYO28資訊網——每日最新資訊28at.com

JVM必然是有自己的一套方法來判斷哪些對象該回收,哪些不該回收。QYO28資訊網——每日最新資訊28at.com

本篇文章就來聊聊這個話題。QYO28資訊網——每日最新資訊28at.com

QYO28資訊網——每日最新資訊28at.com

通過這個例子我們可以看出引用計數法是存在弊端的。QYO28資訊網——每日最新資訊28at.com

所以HotSpot虛擬機并不是通過引用計數算法來判斷對象是否存活的,使用的是「可達性分析算法」。QYO28資訊網——每日最新資訊28at.com

二、可達性分析算法

JVM通過可達性分析(Reachability Analysis)算法來判定對象是否存活的。QYO28資訊網——每日最新資訊28at.com

這個算法的基本思路就是通過一系列稱為GC Roots的根對象作為起始節點集,從這些節點開始,根據引用關系向下搜索。QYO28資訊網——每日最新資訊28at.com

搜索過程所走過的路徑稱為引用鏈(Reference Chain),如果某個對象到GC Roots間沒有任何引用鏈相連,或者用圖論的話來說就是從GC Roots到這個對象不可達時,則證明此對象是不可能再被使用的。QYO28資訊網——每日最新資訊28at.com

QYO28資訊網——每日最新資訊28at.com

如圖,對象object 5、object 6、object 7到GC Roots是不可達的,因此它們將會被判定為可回收的對象。QYO28資訊網——每日最新資訊28at.com

上文提到的GC Roots,我們可以認為是起點,而在JVM里面,固定可以作為GC Roots的對象包括以下幾種:QYO28資訊網——每日最新資訊28at.com

  • 在虛擬機棧(棧中 的本地變量表)中引用的對象,例如各個線程被調用的方法堆棧中使用到的參數、局部變量、臨時變量等。
  • 在方法區中常量引用的對象,例如字符串常量池(String Table)里的引用。
  • 在本地方法棧中JNI(本地方法)引用的對象。
  • Java虛擬機內部的引用,如基本數據類型對應的Class對象,一些常駐的異常對象(NullPointException、OutOfMemoryError)等,以及系統類加載器。
  • 所有被同步鎖(synchronized)持有的對象。
  • 反映Java虛擬機內部情況的JMXBean、JVMTI中注冊的回調、本地代碼緩存等。

通過枚舉一個一個根節點(GC Roots),然后順藤摸瓜一路摸下來,然后沒摸到的那些對象,也就是不存在引用的對象就把它咔嚓回收了。這個過程稱之為「根節點枚舉」。QYO28資訊網——每日最新資訊28at.com

目前所有的垃圾收集器在根節點枚舉這一步驟時都是必須暫停用戶線程的,也就是必須會有STW(Stop the Wrold)。QYO28資訊網——每日最新資訊28at.com

這里面細講東西很多,先埋個坑,后續會有文章專門來講根節點枚舉。QYO28資訊網——每日最新資訊28at.com

QYO28資訊網——每日最新資訊28at.com

看到這里有個疑問,在可達性分析算法中判定為不可達的對象,就一定「非死不可」嗎?QYO28資訊網——每日最新資訊28at.com

四、Dead Or Alive

當一個對象被判斷為不可達的時候,這時候該對象處在「緩刑」階段。QYO28資訊網——每日最新資訊28at.com

意思就是說刀已經架你脖子上了,但是還沒落下來,還是有商量的余地的。QYO28資訊網——每日最新資訊28at.com

要真正宣告一個對象死亡,至少要經歷兩次標記過程:QYO28資訊網——每日最新資訊28at.com

如果對象在進行可達性分析后發現沒有與GC Roots相連接的引用鏈,那它將會被第一次標記,隨后進行一次篩選,篩選的條件是此對象是否有必要執行finalize()方法。QYO28資訊網——每日最新資訊28at.com

假如對象沒有覆蓋finalize()方法,或者finalize()方法已經被虛擬機調用過,那么虛擬機將這兩種情況都視為“沒有必要執行”。QYO28資訊網——每日最新資訊28at.com

如果這個對象被判定為確有必要執行finalize()方法,那么該對象將會被放置在一個名為F-Queue的隊列之中,并在稍后由一條由虛擬機自動建立的、低調度優先級的Finalizer線程去執行它們的finalize()方法。QYO28資訊網——每日最新資訊28at.com

這里所說的“執行”是指虛擬機會觸發這個方法開始運行,但并不承諾一定會等待它運行結束。QYO28資訊網——每日最新資訊28at.com

這樣做的原因是,如果某個對象finalize()方法執行緩慢,或者更極端地發生了死循環,將很可能導致F-Queue隊列中的其他對象永久處于等待,卡死在這里。甚至導致整個內存回收子系統的崩潰。QYO28資訊網——每日最新資訊28at.com

finalize()方法是對象逃脫死亡命運的最后一次機會,救命的最后一根稻草,稍后收集器將對F-Queue中的對象進行第二次小規模的標記。QYO28資訊網——每日最新資訊28at.com

如果對象要在finalize()中成功拯救自己——只要重新與引用鏈上的任何一個對象建立關聯即可,譬如把自己(this關鍵字)賦值給某個類變量或者對象的成員變量,那在第二次標記時它將被移出「即將回收」的集合。QYO28資訊網——每日最新資訊28at.com

如果對象這時候還沒有逃脫,那基本上它就真的要被回收了,就真要說byebye了。QYO28資訊網——每日最新資訊28at.com

需要注意的是:任何一個對象的finalize()方法都只會被系統自動調用一次,如果對象面臨下一次回收,它的finalize()方法不會被再次執行,不能指望我每次都救你,我只能救你一次,剩下的就靠你自己了。QYO28資訊網——每日最新資訊28at.com

看起來對象能夠使用finalize()方法實現自我救贖,然而這個方法并沒有什么用,放一段《深入理解Java虛擬機》里的原話:QYO28資訊網——每日最新資訊28at.com

QYO28資訊網——每日最新資訊28at.com

總結一下,就是finalize()這個方法并沒什么卵用,大家還是把他忘了好。QYO28資訊網——每日最新資訊28at.com

QYO28資訊網——每日最新資訊28at.com

有些人認為方法區(如HotSpot虛擬機中的元空間或者永久代)是沒有垃圾收集行為的,但其實方法區是可以被回收的,只不過回收的判定條件過于苛刻,垃圾收集的成果很差。QYO28資訊網——每日最新資訊28at.com

并不是名字叫永久代就真的「永久」了,出來混,欠的債總要還的。QYO28資訊網——每日最新資訊28at.com

我們先搞清楚方法區要回收的是什么,方法區的垃圾收集主要回收兩部分內容:「廢棄的常量」和「不再使用的類型」。QYO28資訊網——每日最新資訊28at.com

判定一個常量是否“廢棄”還是相對簡單,看這個常量有沒有在用就行了,而要判定一個類型是否屬于「不再被使用的類」的條件就比較苛刻了。需要同時滿足下面三個條件(注意是同時!):QYO28資訊網——每日最新資訊28at.com

  • 該類所有的實例都已經被回收,也就是Java堆中不存在該類及其任何派生子類的實例。
  • 加載該類的類加載器已經被回收,這個條件除非是經過精心設計的可替換類加載器的場景,如OSGi、JSP的重加載等,否則通常是很難達成的。
  • 該類對應的java.lang.Class對象沒有在任何地方被引用,無法在任何地方通過反射訪問該類的方法。

Java虛擬機被允許對滿足上述三個條件的無用類進行回收,這里說的僅僅是“被允許”,而并不是和對象一樣,沒有引用了就必然會回收。QYO28資訊網——每日最新資訊28at.com

關于是否要對類型進行回收,HotSpot虛擬機提供了-Xnoclassgc參數進行控制。QYO28資訊網——每日最新資訊28at.com

對于Oracle的HotSpot JVM,這個參數默認是不開啟的,意味著默認情況下,類元數據可以被垃圾收集器回收。如果你明確使用了 -Xnoclassgc 參數來啟動JVM,那么就會禁止類的垃圾回收。QYO28資訊網——每日最新資訊28at.com

也就是說如果沒有開啟這項參數支持類型的卸載,哪怕滿足了所有條件,也不會進行類型的卸載。QYO28資訊網——每日最新資訊28at.com

上面我們講了對象回收的條件,知道了回收的條件之后,我們再講講怎么被回收,也就是垃圾回收算法。QYO28資訊網——每日最新資訊28at.com

這塊可是面試重點,面試問到JVM這塊少不了要被教育一番,大家好好聽,下次可以跟面試官對波線。QYO28資訊網——每日最新資訊28at.com

六、垃圾收集算法

垃圾收集(Garbage Collection,GC)算法是Java虛擬機(JVM)用來自動管理內存的一種方式。主要的目標是找出那些已經不再使用的對象,并釋放它們所占用的內存空間。QYO28資訊網——每日最新資訊28at.com

通俗來說就是發現垃圾之后怎么收垃圾,是打包帶走,還是來個垃圾分類。QYO28資訊網——每日最新資訊28at.com

1.標記-清除算法

標記-清除算法是最早出現也是最基礎的垃圾收集算法。QYO28資訊網——每日最新資訊28at.com

它分為「標記」和「清除」兩個階段:首先標記出所有需要回收的對象,在標記完成后,統一回收掉所有被標記的對象,也可以反過來,標記存活的對象,統一回收所有未被標記的對象。QYO28資訊網——每日最新資訊28at.com

下圖為使用“標記-清除”算法回收前后的狀態:QYO28資訊網——每日最新資訊28at.com

QYO28資訊網——每日最新資訊28at.com

優點:不需要進行對象的移動,在存活對象比較多的情況下非常高效。QYO28資訊網——每日最新資訊28at.com

缺點:標記-清除算法主要缺點有兩個:QYO28資訊網——每日最新資訊28at.com

  • 第一個是執行效率不穩定,如果Java堆中包含大量對象,而且其中大部分是需要被回收的,這時必須進行大量標記和清除的動作。
  • 第二個是內存空間的碎片化問題,標記、清除之后會產生大量不連續的「內存碎片」,而內存碎片是無法被分配對象的,內存碎片太多可能會導致當以后在程序運行過程中需要分配較大對象時無法找到足夠的連續內存而不得不提前觸發另一次垃圾收集動作。

第一個問題其實還好,但是第二個內存碎片是個大問題,無法容忍。試想一下就跟你打游戲,玩著越來越卡,玩一秒卡二秒,這還怎么玩?QYO28資訊網——每日最新資訊28at.com

所以后續的收集算法大多都是以標記-清除算法為基礎,改進了內存碎片的問題,對其缺點進行改進而得到的。QYO28資訊網——每日最新資訊28at.com

2.標記-復制算法

為了解決標記-清除算法面對大量可回收對象時執行效率低的問題,1969年Fenichel提出了一種稱為「半區復制(Semispace Copying)」的垃圾收集算法。QYO28資訊網——每日最新資訊28at.com

它將可用內存按容量劃分為大小相等的兩塊,每次只使用其中的一塊。當這一塊的內存用完了,就將還存活著的對象復制到另外一塊上面,然后再把已使用過的內存空間一次清理掉。QYO28資訊網——每日最新資訊28at.com

QYO28資訊網——每日最新資訊28at.com

如果內存中多數對象都是存活的,這種算法將會產生大量的內存間復制的開銷,但對于多數對象都是可回收的情況,算法需要復制的就是占少數的存活對象,而且每次都是針對整個半區進行內存回收,分配內存時也就不用考慮有空間碎片的復雜情況。QYO28資訊網——每日最新資訊28at.com

所以,標記-復制算法通常用在新生代的Eden區和Survivor區,這兩個區的對象,朝生夕死,多數對象都是可回收的。QYO28資訊網——每日最新資訊28at.com

總結一下,標記-復制算法有如下優點和缺點:QYO28資訊網——每日最新資訊28at.com

  • 優點:實現簡單,內存回收時不用考慮內存碎片的出現。
  • 缺點:代價是將可用內存縮小為了原來的一半,并且在對象存活率較高時就要進行較多的復制操作,效率將會降低。

下圖為使用復制算法回收前后的狀態:QYO28資訊網——每日最新資訊28at.com

QYO28資訊網——每日最新資訊28at.com

標記-復制看著還行,但是比較大的缺點是浪費了50%的空間,要知道內存是很貴的啊。QYO28資訊網——每日最新資訊28at.com

3.標記-整理算法

標記-復制算法在對象存活率較高時就要進行較多的復制操作,效率將會降低。QYO28資訊網——每日最新資訊28at.com

更關鍵的是,如果不想浪費50%的空間,就需要有額外的空間進行分配擔保,以應對被使用的內存中所有對象都100%存活的極端情況。QYO28資訊網——每日最新資訊28at.com

所以在老年代一般不能直接選用這種算法。針對老年代對象的存亡特征,1974年Edward Lueders提出了另外一種有針對性的標記-整理(Mark-Compact)算法。QYO28資訊網——每日最新資訊28at.com

其中的標記過程仍然與“標記-清除”算法一樣,但后續步驟不是直接對可回收對象進行清理,而是讓所有存活的對象都向內存空間一端移動,然后直接清理掉邊界以外的內存。QYO28資訊網——每日最新資訊28at.com

QYO28資訊網——每日最新資訊28at.com

  • 優點:經過整理之后,新對象的分配只需要通過指針碰撞便能完成,也解決了內存碎片的問題。
  • 缺點:GC 暫停的時間會增長,對象移動的時間成本是十分可觀的。

下圖為使用“標記-整理”算法回收前后的狀態:QYO28資訊網——每日最新資訊28at.com

QYO28資訊網——每日最新資訊28at.com

4.標記-清除 VS 標記-整理

標記-清除算法與標記-整理算法的本質差異在于前者是一種「非移動式」的回收算法,而后者是「移動式」的。QYO28資訊網——每日最新資訊28at.com

別小看這一差異,是否移動回收后的存活對象是一項優缺點并存的風險決策。QYO28資訊網——每日最新資訊28at.com

如果移動存活對象,尤其是在老年代這種每次回收都有大量對象存活區域,移動存活對象會是一種極為負重的操作,而且這種對象移動操作必須全程暫停用戶應用程序才能進行。QYO28資訊網——每日最新資訊28at.com

但如果跟標記-清除算法那樣完全不考慮移動和整理存活對象的話,彌散于堆中的存活對象導致的內存碎片問題就只能依賴更為復雜的內存分配器和內存訪問器來解決。QYO28資訊網——每日最新資訊28at.com

譬如通過「分區空閑分配鏈表」來解決內存分配問題。QYO28資訊網——每日最新資訊28at.com

內存的訪問是用戶程序最頻繁的操作,甚至都沒有之一,假如在這個環節上增加了額外的負擔,勢必會直接影響應用程序的吞吐量。QYO28資訊網——每日最新資訊28at.com

基于以上兩點,是否移動對象都存在弊端,移動則內存回收時會更復雜,不移動則內存分配時會更復雜。從垃圾收集的停頓時間來看,不移動對象停頓時間會更短,但是從整個程序的吞吐量來看,移動對象會更劃算。QYO28資訊網——每日最新資訊28at.com

HotSpot虛擬機里面關注吞吐量的Parallel Scavenge收集器是基于標記-整理算法的,而關注延遲的CMS收集器則是基于標記-清除算法的,這也從側面印證這點。QYO28資訊網——每日最新資訊28at.com

另外,還有一種「和稀泥式」解決方案可以不在內存分配和訪問上增加太大額外負擔,做法是讓虛擬機平時多數時間都采用標記-清除算法,暫時容忍內存碎片的存在,直到內存空間的碎片化程度已經大到影響對象分配時,再采用標記-整理算法收集一次,以獲得規整的內存空間。QYO28資訊網——每日最新資訊28at.com

基于標記-清除算法的CMS收集器采用的就是這種處理辦法。QYO28資訊網——每日最新資訊28at.com

當CMS出現「并發失敗”(Concurrent Mode Failure)」時,這時會啟用Serial Old收集器來重新進行老年代的垃圾收集,而Serial Old正是基于標記-整理算法。QYO28資訊網——每日最新資訊28at.com

好了,本篇文章到這就結束了,這篇文章主要是講JVM是怎么回收對象的,明白了這個,JVM算是初窺門徑了。QYO28資訊網——每日最新資訊28at.com

本文鏈接:http://www.www897cc.com/showinfo-26-12758-0.html面試官:JVM是如何判定對象已死的?學JVM必會的知識!

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: XGBoost 2.0:對基于樹的方法進行了重大更新

下一篇: 九個用于前端開發的Python 框架:JavaScript 替代品

標簽:
  • 熱門焦點
Top 主站蜘蛛池模板: 日土县| 新巴尔虎右旗| 博野县| 汉阴县| 玉田县| 鄂尔多斯市| 乳源| 仪征市| 天峻县| 南昌市| 靖边县| 蕲春县| 商南县| 湖州市| 连平县| 奎屯市| 邳州市| 常熟市| 邹平县| 秭归县| 师宗县| 汉阴县| 双流县| 盐津县| 陆川县| 炉霍县| 桂林市| 南城县| 海宁市| 开鲁县| 安塞县| 凤翔县| 沈丘县| 新野县| 怀安县| 夏津县| 镇坪县| 司法| 湖州市| 罗定市| 龙川县|