1. 程式人生 > >簡述java GC工作機制原理,或你瞭解的GC演算法?

簡述java GC工作機制原理,或你瞭解的GC演算法?

  GC:垃圾回收站,是將java的無用的堆物件進行清理,釋放記憶體,以免發生記憶體洩露。在介紹java回收站前,首先介紹下幾種回收機制

  1. 引用計數:

  當一個物件A被其他物件B引用時,物件A引用+1,斷開引用則-1,GC工作時,會檢查所有物件中的引用計數,如果為0則代表要清除,>0則表示有其他物件引用不能清除。這種機制有一個致命缺點,就是當兩個物件互引用時,在遍歷時可能會發生這兩個物件引數永遠不為0,則永遠不會被刪除。此機制java從不使用。

  2. 停止-複製:

程式暫停執行,啟動GC,GC從堆或靜態儲存區開始遍歷所有物件,判斷物件是否“活”的物件,如果是活不刪除,反之刪除。判斷是否“活”就是判斷該物件是否有被其他物件引用,從鏈上去查詢。當是活物件時,GC會從另外堆裡開避一個大空間,然後將活物件複製一份到新空間裡,在複製時按著緊密排列,同時更新所有引用地址為新的地址,不活物件原封不動。遍歷完後,再遍歷一次,這次是將不活的物件徹底給刪除。

  優點:所有物件能夠重新緊密排列,不會出現記憶體碎片,這對以後建立物件能提供更快的效率。

  缺點:佔用的記憶體空間大,要原物件的2倍空間;這種模式無論如何所有活的物件都要複製一份,假設遍歷到最後,物件很穩定,只出現少量垃圾物件或者根本沒垃圾物件,這時已經做了複製工作,浪費了資源。

  3. 標記-刪除:

程式暫停執行,啟動GC,GC從堆或靜態儲存區開始遍歷所有物件,判斷物件是否“活”的物件,如果是活不刪除,反之刪除。判斷是否“活”就是判斷該物件是否有被其他物件引用,從鏈上去查詢。當是活物件時,會給物件給個標記符號,死物件則不標記,遍歷完後,第二次遍歷時,只保留標記的物件,把所有沒標記的物件都刪除。

  以上第2和第3種都是要遍歷兩次,而且都是最後一次才執行真正刪除,比起第1種來說要慢很多,因為要遍歷2次,尤其是第2種,還要複製動作,但這2種歸避了第1種的致命缺點。

  早期的jvm採用的是標記-刪除模式,繼java5後,jvm採用自適應技術,就是根據自身狀態情況,在”停止-複製“和”標記-刪除“自動切換以達到最快效率。在第1遍歷時,如果確定物件需要回收,則會先執行物件的finalize()方法。

  java GC具體工作原理:

  JVM分配記憶體是以較大的塊為單位,如果物件為較大,則該物件本身為一個塊。GC先啟動“停止-複製”模式,遍歷物件時,遇到活物件,則把物件複製到新塊裡,同時塊代數+1,如果物件較大,則保持不動,代數+1;如果檢測到垃圾物件稀少,則自動切換到“標記-刪除”模式,如果檢測到物件分佈到記憶體太零散,則又會自動切換到“停止-複製”模式來重新整理記憶體緊密分佈。這就是自適應技術。

  JVM分配記憶體時,有一個堆指標,堆指標指向當前最後一個被分配的記憶體塊,由於“停止-複製”模式,物件大部分都是連續排列的,則堆指標移動下一格,就是尚未分配的記憶體,這時就不用在整個堆空間裡查詢未分配的記憶體了,這對建立速度有很大提高。

  關於物件的finalize()方法:

finalize方法是指物件完成時執行的一些清理工作,是Object裡的受保護方法,在外界不能呼叫。實質上這個方法是給GC呼叫的,什麼時候呼叫以上有講。此方法是強調進一步物件需要釋放非託管物件,是一個檢測保險的作用,比如一個類裡包含訪問一個流內容,如下: 

class AccessStream
{
private InputStream stream;

private boolean isClose = false;

/* (non-Javadoc)
* @see java.lang.Object#finalize()
*/
@Override
protected void finalize() throws Throwable
{
if (!isClose)
{
stream.close();
}
super.finalize();
}
}

   此類在操作流完後,正確作法是,應該即時關閉流(呼叫close());有時因為程式設計師某些租心大意原因,並沒及時關閉流,這時重寫finalize() 作最後保險作用,當沒有關閉時,釋放此物件前關閉流。

  通常不建議重寫finalize,除了要求程式設計師嚴格習慣,最重要的是finalize並不能馬上執行,即使是顯式呼叫System.gc() 也不保證立刻執行,只能說建議GC執行,GC是否要執行,要看當前記憶體佔用量等因素。如果finalize不能馬上執行,這就意味著本來應該早點釋放流,而出現很長時間才釋放。

GC演算法?

在C/C++中是由程式設計師自己去申請、管理和釋放記憶體的,因此沒有GC的概念。而在Java中,專門有一個用於垃圾回收的後臺執行緒來進行監控、掃描,自動將一些無用的記憶體進行釋放。下面介紹幾種常見的GC演算法。

引用計數法 Reference Counting

給物件新增一個引用計數器,每過一個引用計數器值就+1,少一個引用就-1。當它的引用變為0時,該物件就不能再被使用。它的實現簡單,但是不能解決互相迴圈引用的問題。

根搜尋演算法 GC Roots Tracing

以一系列叫“GC Roots”的物件為起點開始向下搜尋,走過的路徑稱為引用鏈(Reference Chain),當一個物件沒有和任何引用鏈相連時,證明此物件是不可用的,用圖論的說法是不可達的。那麼它就會被判定為是可回收的物件。

JAVA裡可作為GC Roots的物件 
虛擬機器棧(棧幀中的本地變量表)中引用的物件 
方法區中的類靜態屬性引用的物件 
方法區中的常量引用的物件 
本地方法棧中JNI(即Native方法)的引用的物件

標記-清除演算法 Mark-Sweep

這是一個非常基本的GC演算法,它是現代GC演算法的思想基礎,分為標記和清除兩個階段:先把所有活動的物件標記出來,然後把沒有被標記的物件統一清除掉。但是它有兩個問題,一是效率問題,兩個過程的效率都不高。二是空間問題,清除之後會產生大量不連續的記憶體。

這裡寫圖片描述

複製演算法 Copying

複製演算法是將原有的記憶體空間分成兩塊,每次只使用其中的一塊。在GC時,將正在使用的記憶體塊中的存活物件複製到未使用的那一塊中,然後清除正在使用的記憶體塊中的所有物件,並交換兩塊記憶體的角色,完成一次垃圾回收。它比標記-清除演算法要高效,但不適用於存活物件較多的記憶體,因為複製的時候會有較多的時間消耗。它的致命缺點是會有一半的記憶體浪費。

這裡寫圖片描述

標記整理演算法 Mark-Compact

標記整理演算法適用於存活物件較多的場合,它的標記階段和標記-清除演算法中的一樣。整理階段是將所有存活的物件壓縮到記憶體的一端,之後清理邊界外所有的空間。它的效率也不高。

這裡寫圖片描述

相關推薦

簡述java GC工作機制原理瞭解GC演算法

  GC:垃圾回收站,是將java的無用的堆物件進行清理,釋放記憶體,以免發生記憶體洩露。在介紹java回收站前,首先介紹下幾種回收機制  1. 引用計數:  當一個物件A被其他物件B引用時,物件A引用+1,斷開引用則-1,GC工作時,會檢查所有物件中的引用計數,如果為0則代表要清除,>0則表示有其他物

業余草分享面試題JVM結構、GC工作機制詳解

影響 根節點 tac 關註 共享 產生 我想 tar 效果 題外話:最近在應聘阿裏2015暑期實習,感觸頗多。機會總是留給有準備的人的,所以平常一定要註意知識的鞏固和積累。知識的深度也要有一定的理解,不比別人知道的多,公司幹嘛選你?關於JVM和GC,我相信學java的絕大部

JVM 的 工作原理層次結構 以及 GC工作原理

JVM Java 虛擬機器 Java 虛擬機器(Java virtual machine,JVM)是執行 Java 程式必不可少的機制。JVM實現了Java語言最重要的特徵:即平臺無關性。原理:編譯後的 Java 程式指令並不直接在硬體系統的 CPU 上執行,而是由 J

Java GC工作機制 //TODO

感謝 千古壹號 公眾號的分享 以下為自己看了這篇文章後的整理記錄,方便記憶及複習。 GC的概念 GC:Garbage Collections 字面意思是垃圾回收器,釋放垃圾佔用的空間。讓建立的物件不需要像c、c++那樣需要程式設計師手動的delete、free掉

java GC工作機制

  GC:垃圾回收站,是將java的無用的堆物件進行清理,釋放記憶體,以免發生記憶體洩露。在介紹java回收站前,首先介紹下幾種回收機制   1. 引用計數:   當一個物件A被其他物件B引用時,物件A引用+1,斷開引用則-1,GC工作時,會檢查所有物件中的引用計數,如果為0則代表要清除,>0則表示

jvm原理記憶體模型及GC機制

1. jvm記憶體模型 程式計數器、本地方法棧、方法區、Java棧、Java堆及其他隱含暫存器。 1.1 程式計數器: 程式計數器是一塊較小的記憶體空間,可以看作是當前執行緒所執行的位元組碼的行號指示器。分支、迴圈、跳轉、異常處理、執行緒恢復等基礎功能都需要依賴這個

Java 垃圾回收機制(以及怎麼減少呼叫GC提高效能)

 綜合了若干人的blog~ 1. 垃圾回收的意義  在C++中,物件所佔的記憶體在程式結束執行之前一直被佔用,在明確釋放之前不能分配給其它物件;而在Java中,當沒有物件引用指向原先分配給某個物件的記憶體時,該記憶體便成為垃圾。JVM的一個系統級執行緒會自動釋放該記憶體

JVM結構、GC工作機制詳解

固定 本地方法棧 內存池 為什麽 water aml 並且 兩種 數據區 轉自:http://blog.csdn.net/tonytfjing/article/details/44278233 JVM結構、內存分配、垃圾回收算法、垃圾收集器。下面我們一一來看。 一、JVM結

java的反射機制原理

動態調用 clas java語言 動態 方法 gpo mod odi log 一 反射機制的概念: 指在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法,對於任意一個對象,都能調用它的任意一個方法.這種動態獲取信息,以及動態調用對象方法的功能叫java語言的反

JVM、Gc工作機制詳解

相同 生命 棧幀 VM 每次 失效 劃分 地址 .com JVM主要包括四個部分: 類加載器(ClassLoad) 執行引擎 內存區: 本地方法接口:類似於jni調本地native方法 內存區包括四個部分: 1.方法區:包含了靜態變量、常量池、構造函數等

java——HashMap的實現原理自己實現簡單的HashMap

資料結構中有陣列和連結串列來實現對資料的儲存,但是陣列儲存區間是連續的,定址容易,插入和刪除困難;而連結串列的空間是離散的,因此定址困難,插入和刪除容易。 因此,綜合了二者的優勢,我們可以設計一種資料結構——雜湊表(hash table),它定址、插入和刪除都很方便。在ja

Java】Iterator底層原理自己實現Iterator

package test; import java.util.Iterator; public class MyIterator implements java.lang.Iterable<String> { private String[] eleme

Java】ArrayList 底層原理自己實現ArrayList

實現的功能有  elementData物件陣列用來存放物件 size 計算容器大小 ArrayList空構造器,帶初始大小的構造器 ensureCapacity進行物件陣列擴容 rangeCheck進行檢查輸入值是否在範圍內 get方法返回某一位置物件 set方

Android訊息機制原理仿寫Handler Looper原始碼解析跨執行緒通訊原理--之仿寫模擬Handler(四)

前篇總結:上一篇實現了用Looper管理訊息佇列和訊息迴圈,但是訊息的傳送和訊息處理都是在Looper中進行的。寫一個子執行緒使用這樣的Looper怎麼才能獲取到loop()死迴圈訊息佇列取出的訊息呢?用回撥!callBack! 第四節 仿寫Handler來發送訊息,實現回

Android訊息機制原理仿寫Handler Looper原始碼跨執行緒通訊原理--之執行緒間通訊原理(一)

前言:我們都知道Android的執行緒通訊是用Handler、Looper機制實現的,面試也經常問道,網上也有很多文章介紹原始碼但是可能很多小白只是機械是的記憶,回答不清楚原理究竟是怎麼回事。下邊我將一步一步仿寫一個Handler、Looper模擬Android的執行緒間通訊

java垃圾回收機制什麼物件會被回收掉?

從GC-root搜尋不到,而且經過第一次標記,清理後,仍然沒有復活的物件。http://www.importnew.com/21492.htmlhttps://www.cnblogs.com/xiaoxi/p/6486852.html

12.Java泛型的原理基本和高階應用

Java泛型的原理,基本和高階應用 1.體驗泛型 (1)Jdk1.5以前的集合類中存在什麼問題? 在1.5之前的jdk,我們使用泛型的方式是這樣,當我們給這個集合中存放了值後,我們想要取值的

GC工作機制詳解

一、JVM結構 根據《java虛擬機器規範》規定,JVM的基本結構一般如下圖所示: 從左圖可知,JVM主要包括四個部分: 1.類載入器(ClassLoader):在JVM啟動時或者在類執行時將需要的class載入到JVM中。(右圖表示了從java原始檔到JVM的整

Java NIO工作機制簡介

前言 本部落格只簡單介紹NIO的原理實現和基本工作流程 I/O和NIO的本質區別 NIO將填充和提取緩衝區的I/O操作轉移到了作業系統 I/O 以流的方式處理資料,而 NIO 以緩衝區的方式處理資料;IO是阻塞的,NIO是非阻塞的,直到有資料被讀取或

了解一下JVM和GC工作機制

今天 載器 執行c 運行時常量 引擎 ati 局部變量 容易 ive 題外話:很久沒有寫博客了,事情頗多,今天空閑下來,學習一下順便寫一下自己的了解,機會總是留給有準備的人,所以平常一定要註意知識的鞏固和積累。知識的深度也要有一定的理解,不比別人知道的多,公司幹嘛選你?