<html>

來源:互聯網
上載者:User

標籤:sdn   賦值   反向   pretty   desc   rda   取消   sky   生產環境   

假設還沒看過第一篇的朋友請移步:JAVA記憶體回收(1)—深入淺出Java記憶體回收機制
 

不論什麼垃圾收集演算法必須完畢兩件事情。首先,它必須檢測出垃圾對象。其次,它必須回收垃圾對象所佔用的堆空間並使之對程式又一次可用。

  垃圾檢測通常通過定義一個根引用集並計算其可達對象集的方式來實現。一個對象,假設能夠通過某條始於根引用的引用路徑而被運行程式訪問到的話,則稱其為可達的(reachable)。對程式而言。根引用始終是能夠訪問的。

一個對象假設是可達的,則稱其為使用中的物件。否則就被稱為垃圾,由於它對程式的未來運行不再有不論什麼影響。
  根引用集的構成取決於JVM的詳細實現,但總是包含全部棧幀中局部變數區和運算元棧所持有的引用以及儲存在靜態變數中的引用。

根引用的另外一個來源是常量池,已裝載類的常量池可能儲存有對堆中一些字串的引用,這些字串往往是類名、父類名、父介面名、網域名稱、域簽名、方法名和方法簽名等。根引用還有一個可能來源就是那些傳遞給本地方法(native method)但尚未被其釋放的引用。根引用的還有一個潛在來源是JVM的運行時資料區,由於某些實現會把JVM運行時資料區的一部分放在堆上,比如方法區中的類資料本身。
  可達對象集包含全部通過根引用能夠直接或間接被程式訪問到的對象。從技術角度講,可達對象集是“指向”關係下根引用集的傳遞閉包。
  區分使用中的物件和垃圾的兩個基本方法是引用計數和追蹤。JDK中的標準垃圾收集器全部採用了追蹤的辦法,儘管詳細形式各不相同。
  

一、引用計數法(Reference Counting Collector)

  引用計數是垃圾收集的早期策略。在這樣的方法中,堆中的每一個對象都有一個引用計數。當對象被建立並且指向其引用被賦值給一個變數後,該對象的引用計數被設定為1。以後每當其引用被賦值給一個不同的變數時,該對象的引用計數就加1。

當持有該對象引用的變數離開其範圍或者被賦給一個新值時。該對象的引用計數就減1。

任一對象一旦其引用計數變為0。就成為垃圾。

一個對象一旦被當作垃圾收集後,它所引用的全部其它對象的引用計數必須對應遞減。這樣。對一個對象的垃圾收集可能引發連續的對其它對象的垃圾收集。


  該方法的優點是。引用計數收集器演算法簡單,適於做增量收集,對於程式不能被長時間打斷的即時環境特別適合。另外。收集過程也有助於改進引用局部性。

壞處就是,引用計數無法檢測出不可達的迴圈結構(兩個或多個對象之間相互引用)。由於它們的引用計數永遠不會為0。

還有一個壞處就是每次增減引用計數都帶來額外開銷。並且該演算法還須要編譯器的高度配合。正是由於這些固有缺陷,引用計數演算法在生產環境中非常少使用。


 

二、 tracing演算法(Tracing Collector)

  追蹤收集器從根引用開始探尋並描畫對象引用圖。探尋過程中遇到的對象會以某種方式被打上標記。

通常來說該標記既可儲存在對象本身,也可儲存在單獨的位元影像中。

探尋結束後未被標記的對象就是不可達的對象,可被當作垃圾收集。
  主要的追蹤演算法被稱作“標記並清理”(mark and sweep)。

該名字指出了垃圾收集過程的兩個階段。在標記階段。垃圾收集器遍曆引用樹,標記每一個遇到的對象。在清理階段,未被標記的對象被釋放,對應記憶體被返還待用。在JVM中,清理階段必須包含對象的了結(finalization)。


  標記並清理演算法實現簡單,能夠輕易回收迴圈結構。並且不存在為維護引用計數而付出的額外開銷和對編譯器的依賴。可是它也有不足,當中最大的問題是,在清理階段,堆中的全部對象,不論是否可達,都會被訪問。

一方面這對於可能有頁面交換的堆所依賴的虛存系統有著非常負面的效能影響;還有一方面。由於當中非常大一部分對象可能是垃圾,這就意味著垃圾收集器把大量精力都花費在檢查和處理垃圾上面了。不管從哪個角度來看。該演算法都可能產生收集暫停時間過長、收集開銷偏大的問題。標記並清理收集器的還有一個不足是它easy導致堆的片段化,從而引發引用局部性或者大對象分配失敗等方面的問題。
在主流的商用程式語言(Java、C#。甚至包含前面提到的古老的Lisp)的主流實現中,都是稱通過可達性分析(Reachability Analysis)來判定對象是否存活的。這個演算法的基本思路就是通過一系列的稱為“GC Roots”的對象作為起始點,從這些節點開始向下搜尋,搜尋所走過的路徑稱為引用鏈(Reference Chain),當一個對象到GC Roots沒有不論什麼引用鏈相連(用圖論的話來說,就是從GC Roots到這個對象不可達)時,則證明此對象是停用。3-1所看到的,對象object 5、object 6、object 7儘管互相有關聯,可是它們到GC Roots是不可達的,所以它們將會被判定為是可回收的對象。

在Java語言中,可作為GC Roots的對象包含以下幾種:

虛擬機器棧(棧幀中的本地變數表)中引用的對象。

方法區中類靜態屬性引用的對象。

方法區中常量引用的對象。

本地方法棧中JNI(即一般說的Native方法)引用的對象

三、compacting演算法(Compacting Collector)

  JVM的垃圾收集器非常可能擁有一個對付堆片段的策略。

標記並清理收集器通常採用的兩種策略是壓縮或拷貝。

這兩種方法都是通過高速移動對象來降低堆片段。壓縮收集器把使用中的物件越過空暇記憶體區滑動到堆的一端,在這個過程中,堆的還有一端就變成了一塊大的連續空暇區。

全部指向被移動對象的引用也被更新,指向新的位置。
  為了更好的理解壓縮過程,能夠將堆比作書架的一格。當中一部分放滿了不同厚度的圖書。空暇空間就是圖書之間的空隙。壓縮就是將全部圖書朝一個方向推移,以彌合全部空隙。

它從最靠近隔板的圖書開始。將它推向隔板,然後將離隔板第二近的圖書推向第一本圖書。接著將第三本圖書推向第二本圖書,依此類推。最後,全部圖書在一端,全部空暇空間在還有一端。


  被移動對象的引用更新能夠通過為對象引用加入一層間址而得到簡化。對象引用不再直接指向堆中的對象。而是指向物件控點表中的一個表項,該表項中的物件控點才直接指向堆中的實際對象。

這樣。當對象被移動時,僅僅需在物件控點表中更新其控制代碼,運行程式中全部指向該對象的引用都不必再更新。這樣的方法簡化了消除堆片段的工作,但添加了每一次對象存取的開銷。


  

四、copying演算法(Coping Collector)

  拷貝收集器相同使用追蹤技術,它把全部的使用中的物件移動到一個新的地區,而原有地區就全部變成了空暇空間。由於被移動對象在新的地區中被緊挨著放置。因而在原有地區時對象之間可能存在的空隙也被消除。

對象的拷貝能夠在追蹤過程中即時進行,不必通過標記和清理兩個單獨的階段來完畢。對象被即時複製到新的地區後,它在原有地區中的副本被一個轉向指標(forwarding pointer)所代替,該指標指向該對象在新的地區中的副本。轉向指標讓垃圾收集器檢測出那些引用(其所指對象已經被移動到新的地區中)並以轉向指標的值更新之,從而使它們指向對象的新位置。


  一個通用的拷貝收集器演算法被稱作“停止並拷貝”(stop and copy)。在這個方法中,堆被分成兩個地區,不論什麼時候都僅僅使用當中的一個地區。

對象在同一地區中分配,直到該地區的全部空間被耗盡。

此時,程式運行被中止。堆被遍曆,遍曆過程中遇到的使用中的物件被複製到堆的還有一個地區。當停止並拷貝過程完畢後,程式恢複運行。對象的記憶體將從堆的這個新地區中分配,直到它也被用盡。那時程式將被再次中止。堆被遍曆。使用中的物件被拷貝回原來的地區。該方案的代價是所需記憶體是指定堆空間的兩倍。由於不論何時都僅僅有一半的記憶體被使用。
  拷貝收集演算法的優點是僅僅訪問使用中的物件。垃圾對象不會被檢查。自然也無需被換頁到記憶體或被緩衝。收集過程所用時間僅僅取決於使用中的物件的數量。這樣既避免了不必要的收集開銷。又最大限度地降低了收集暫停時間。只是。除了額外的記憶體消耗外,拷貝收集器還須要承擔對象拷貝和引用更新所帶來的成本添加。這一點在長壽對象較多時體現得更為明顯,由於每次收集時它們都要被來回複製。
  

五、generation演算法(Generational Collector)

  通過觀察和實驗,對多種語言所寫的大多數應用程式而言,它們所建立的對象都具有例如以下特徵:1)大部分對象的壽命都非常短。但總有一些對象會活得足夠長;2)年長對象非常少引用年幼對象。以上事實也被稱作“弱代假說”(weak generational hypothesis),它是分代收集演算法的前提和基礎。
  在這樣的方法中,對象依照年齡分成組(代),堆則被劃分成兩個或多個子堆,每一個子堆服務於一代對象,因此子堆也經常被稱作某某代。最年幼代被進行最頻繁的垃圾收集。

由於大部分對象的壽命都非常短,所以僅僅有非常小一部分的最年幼對象經曆首次收集後還能存活。

假設一個最年幼對象在經曆幾次垃圾收集後依舊存活,那麼它將被提升到壽命更高的一代(被移動到還有一個子堆中去)。

與相對年幼代比較。相對年長代被垃圾收集的頻率總會有所降低。

隨著對象在其當前代中的不斷成熟(經曆多次垃圾收集而不死),終於它們會被移動到較其當前代更為年長的一代中。


  分代收集技術既可應用於拷貝演算法,以解決它在處理長壽對象時效率低下的問題,也可應用於標記並清理演算法。不管在哪種情況下,把堆劃分為對象代都有助於提高最主要的垃圾收集演算法的效率。


 

六、adaptive演算法(Adaptive Collector)

  自適應收集演算法利用例如以下事實:一些收集演算法在某些情況下工作的更好,而還有一些則在其它情況下工作的更好。自適應收集器監控堆的目前狀態並據此對其所用垃圾收集技術做對應調整。它可能僅僅在程式啟動並執行同一時候對單一收集演算法的參數做出調整。也可能從一種演算法高速切換到還有一種演算法,甚或還可能把堆劃分為子堆並在不同的子堆上同一時候使用不同的演算法。
  使用自適應方法。JVM實現的設計者無需再選擇某種特定的垃圾收集技術。他們能夠使用多種技術,為每種演算法分配最適合它的工作。


  實際上,在現代JVM實現中,大部分垃圾收集子系統都具有某種程度的自適應能力,非常多時候我們僅僅須選擇策略並設定目標便能得到愜意的結果。至於詳細的收集演算法選擇和參數配置則可交由垃圾收集子系統自行處理。Sun的HotSpot JVM中的垃圾處理子系統就是這樣運作的,詳細細節有時間再專門討論。
參考:
1)Cheney’s algorithm
2)Garbage Collection - Chapter 9 of Inside the Java Virtual Machine
3)Java theory and practice: A brief history of garbage collection

閱讀全文 著作權聲明:本文為博主原創文章。未經博主同意不得轉載。

舉報

  • 標籤:
  • java /
  • q=記憶體回收&t=blog" target="_blank">記憶體回收 /

  • 演算法 /
  • 本文已收錄於下面專欄:
0條評論
相關文章推薦
Java基礎惡補——記憶體管理、記憶體回收  ----------------------------------------------------------------------------------------------<p style="text-align: right
  • tvmovie
  • 2010-03-04 13:50
  • 2524
探秘Java虛擬機器——記憶體管理與記憶體回收 探秘Java虛擬機器——記憶體管理與記憶體回收本文主要是基於Sun JDK 1.6 Garbage Collector(畢玄)的整理與總結。原文請讀者在網上搜尋。

1、Java虛擬機器執行時的...

  • cqhweb
  • 2015-03-31 16:36
  • 304
Java 記憶體配置原理及記憶體回收 文章節選至:http://lz12366.iteye.com/blog/640147http://hi.baidu.com/hbeing/blog/item/c708220220ac88034afb516c.htmlhttp://dev.yesky.com/178/2278678.shtml Java 程式執行機制:    JVM是基於堆棧的虛擬機器. <span
  • zl198751
  • 2010-12-21 17:44
  • 715
JVM記憶體段分配,Java記憶體回收調優。Heap設定,Jvm記憶體回收演算法 http://hi.baidu.com/kingtckingtc/blog/item/ca5606f4decd5767ddc4740b.html
  • jadar_ly
  • 2009-11-23 16:28
  • 257
探秘Java虛擬機器——記憶體管理與記憶體回收 探秘Java虛擬機器——記憶體管理與記憶體回收1、Java虛擬機器執行時的資料區2、經常使用的記憶體地區調節參數-Xms:初始堆大小。默覺得實體記憶體的1/64(<1GB)。預設(MinHeapFreeRatio參數能夠調整)空餘堆記憶體小於40%時,JVM就會增大堆直到-Xmx的最大限制-Xmx:最大堆大小,預設(MaxHeapFreeRatio參數能夠調整)空餘堆記憶體大於70%時,JVM會降低堆直到 -Xms的最小限制-Xmn:新生代的記憶體空間大小,注意:此處的大小是(eden+ 2 survivor space)。與jmap -heap中顯示的New gen
  • joe_zhjiang
  • 2012-11-28 23:16
  • 543
探秘Java虛擬機器——記憶體管理與記憶體回收 本文主要是基於Sun JDK 1.6 Garbage Collector(畢玄)的整理與總結,原文請讀者在網上搜尋。1、Java虛擬機器執行時的資料區2、經常使用的記憶體地區調節參數-X...
  • mn11201117
  • 2013-04-08 10:02
  • 608
Java記憶體回收 記憶體回收機制 一、記憶體配置策略一般記憶體粗糙的能夠分為
  • rainyear
  • 2012-11-25 02:11
  • 587
《深入理解java虛擬機器》筆記——第三章 垃圾收集器與記憶體配置策略 第三章3.1 概述 哪些記憶體須要回收? 什麼時候回收? 怎麼回收? 這裡記憶體回收行程關注的是Java堆和方法區的記憶體。程式計數器、虛擬棧、本地方法棧三個地區會隨著線程而生,隨著線程而滅, 不用...
  • sinat_32487221
  • 2017-02-17 17:42
  • 852
探秘Java虛擬機器——記憶體管理與記憶體回收 <h1 class="block_title" style="margin-top: 10px; margin-bottom: 30px; font-size: 14.7px; color: #444444; border-bottom-width: 1px; border-bottom-style: dashed; border-bottom-color: #cccccc; padding-top: 10px; font-family: verdana, ar
  • grefr
  • 2014-06-16 23:29
  • 558
【轉】java記憶體管理及記憶體回收 轉載自:http://blog.csdn.net/sup_heaven/article/details/39157829一、Java記憶體模型Java虛擬機器會將記憶體分為幾個不同的管理區,這些...
  • qq_28385797
  • 2016-12-07 17:04
  • 165
Android developer. +關注
原創
79
粉絲
13
喜歡
0
  • 一句話解決的事何必說三句,Kotlin入坑指南
  • Android透明化/沈浸式狀態列實踐及原始碼分析
  • Bacula虛擬機器設定error:no route to host
  • XMPP 協議工作流程具體解釋
很多其它文章 線上課程
【直播】機器學習&資料採礦7周實訓--韋瑋

utm_source=blog7" target="_blank">【套餐】系統整合專案管理project師順利通關--徐朋

  • 檔案夾
  • 喜歡 取消愛好
  • 收藏
  • 分享 微博 QQ
收藏助手 不良資訊舉報

<html>

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.