做者 某人Valar
如需轉載請保留原文連接
部分圖片來自百度,若有侵權請聯繫刪除html
本文目錄java
GC:垃圾回收(Garbage Collection),在計算機領域就是指當一個計算機上的動態存儲器(內存空間)再也不須要時,就應該予以釋放,以讓出存儲器,便於他用。這種存儲器的資源管理,稱爲垃圾回收。算法
有一些語言是沒有垃圾回收機制的,像
C
、C++
,若是須要釋放無用變量內存空間就由本身來處理。bootstrap而其餘的一些語言如
Java
、C#
都支持垃圾回收器,Java虛擬機(JVM)或.NET CLR發現內存資源緊張的時候,就會自動地去清理無用對象(沒有被引用到的對象)所佔用的內存空間。bash而咱們今天主要講Java中的GC。網絡
上面說到JVM
會自動清理無用的對象,那麼咱們就有了疑問:oracle
JVM
清理的是哪一塊的對象?JVM
又是如何清理的?這三個問題將分別對應接下來的3節一一解答。eclipse
咱們都知道,Java代碼是要運行在虛擬機上的,而虛擬機在執行Java程序的過程當中會把所管理的內存劃分爲若干個不一樣的數據區域,這些區域都有各自的用途。 在《Java虛擬機規範(Java SE 8)》中描述了JVM運行時內存區域結構以下:jvm
以上是Java虛擬機規範,不一樣的虛擬機實現可能會各有不一樣,可是通常會遵照規範jsp
Java中經過可達性分析法來肯定某個對象是否是「垃圾」。
該方法的基本思想是經過一系列的「GC Roots」對象做爲起點進行搜索,若是在「GC Roots」和一個對象之間沒有可達路徑,則稱該對象是不可達的,不過要注意的是被斷定爲不可達的對象不必定就會成爲可回收對象。被斷定爲不可達的對象要成爲可回收對象必須至少經歷兩次標記過程,若是在這兩次標記過程當中仍然沒有逃脫成爲可回收對象的可能性,則基本上就真的成爲可回收對象了。
注意其本質是經過找出全部活對象來把其他空間認定爲「無用」,而不是找出全部死掉的對象並回收它們佔用的空間.
以下圖,當object五、六、7不存在到GC Roots的引用時,即不可到達GC Roots,則斷定他們是不可達的。
對於哪些對象能夠被當成GC Roots網上有不少種說法,有的不夠權威、有的不夠全面。 最終找到了一份eclipse的官方文檔,裏面有以下的介紹: Garbage Collection Roots (本身翻譯了一下,若有不許確的地方,請指出)
A garbage collection root is an object that is accessible from outside the heap. The following reasons make an object a GC root:
1. System Class (被boostrap 或者系統類加載器加載的系統類)
Class loaded by bootstrap/system class loader. For example, everything from the rt.jar like java.util.* .
2. JNI Local( 一些用戶定義jni 代碼或者jvm的內部代碼局部變量)
Local variable in native code, such as user defined JNI code or JVM internal code.
3. JNI Global( jni 代碼中的全局變量)
Global variable in native code, such as user defined JNI code or JVM internal code.
5. Thread Block(被阻塞的線程引用的對象)
Object referred to from a currently active thread block.
6. Thread (正在運行的線程)
A started, but not stopped, thread.
7. Busy Monitor(正在等待的線程)
Everything that has called wait() or notify() or that is synchronized.
For example, by calling synchronized(Object) or by entering a synchronized method.
Static method means class, non-static method means object.
8. Java Local(仍然在線程的棧中的方法的傳入參數或方法內部建立的對象)
Local variable.
For example, input parameters or locally created objects of methods that are still in the stack of a thread.
9.Native Stack(本地方法棧中輸入或輸出參數,例如,用於文件/網絡I/O的方法或反射的參數。)
In or out parameters in native code, such as user defined JNI code or JVM internal code.
This is often the case as many methods have native parts and the objects handled as method parameters become GC roots.
For example, parameters used for file/network I/O methods or reflection.
10.Finalizable(在回收隊列中的對象)
An object which is in a queue awaiting its finalizer to be run.
11. Unfinalized(覆蓋了finalize方法可是尚未被放入回收隊列中的對象)
An object which has a finalize method, but has not been finalized and is not yet on the finalizer queue.
12.Unreachable(一個從任何其餘根沒法訪問的對象,但由Memory Analyzer Tool 標記爲根,以便該對象能夠包含在分析中)
An object which is unreachable from any other root,
but has been marked as a root by MAT to retain objects which otherwise would not be included in the analysis.
13. Java Stack Frame
A Java stack frame, holding local variables.
Only generated when the dump is parsed with the preference set to treat Java stack frames as objects.
14. Unknown
An object of unknown root type. Some dumps, such as IBM Portable Heap Dump files, do not have root information.
For these dumps the MAT parser marks objects
which are have no inbound references or are unreachable from any other root as roots of this type.
This ensures that MAT retains all the objects in the dump.
複製代碼
簡單總結下就是:
這是最基礎的垃圾回收算法,之因此說它是最基礎的是由於它最容易實現,思想也是最簡單的。標記-清除算法分爲兩個階段:標記階段和清除階段。標記階段的任務是標記出全部須要被回收的對象,清除階段就是回收被標記的對象所佔用的空間。具體過程以下圖所示:
優缺點:爲了解決Mark-Sweep算法的缺陷,Copying算法就被提了出來。它將可用內存按容量劃分爲大小相等的兩塊,每次只使用其中的一塊。當這一塊的內存用完了,就將還存活着的對象複製到另一塊上面,而後再把已使用的內存空間一次清理掉,這樣一來就不容易出現內存碎片的問題。具體過程以下圖所示:
優缺點:該算法標記階段和Mark-Sweep同樣,可是在完成標記以後,它不是直接清理可回收對象,而是將存活對象都向一端移動,而後清理掉端邊界之外的內存。具體過程以下圖所示:
優缺點:分代收集算法是目前大部分JVM的垃圾收集器採用的算法。它的核心思想是根據對象存活的生命週期將內存劃分爲若干個不一樣的區域。 通常狀況下將堆區劃分爲老年代(Tenured Generation)和新生代(Young Generation),在HotSpot中,設計者將方法區歸入也歸入了GC分代收集,併爲其起了一個名字,永久代(PerGen space)。
標記-整理(Mark-Compact)
、標記-清除(Mark-Sweep)
算法。取複製(Copying)
算法。由於新生代中每次垃圾回收都要回收大部分對象,也就是說須要複製的操做次數較少,可是實際中並非按照1:1的比例來劃分新生代的空間的,通常來講是將新生代劃分爲一塊較大的Eden空間(伊甸園,亞當和夏娃偷吃禁果生娃娃的地方,用來表示內存首次分配的區域,再貼切不過)和兩塊較小的Survivor空間,每次使用Eden空間和其中的一塊Survivor空間,當進行回收時,將Eden和Survivor中還存活的對象複製到另外一塊Survivor空間中,而後清理掉Eden和剛纔使用過的Survivor空間。通常來講分配比例爲eden 80%、survivor1 10%、survivor2 10%。
在方法區進行垃圾回收通常」性價比」較低, 由於在方法區主要回收兩部份內容: 廢棄常量和無用的類。 回收廢棄常量與回收其餘年代中的對象相似, 但要判斷一個類是否無用須要如下條件:
- 該類全部的實例都已經被回收, Java堆中不存在該類的
任何實例
;- 該類對應的
Class對象
沒有在任何地方被引用(也就是在任何地方都沒法經過反射訪問該類的方法);- 加載該類的
ClassLoader
已經被回收。但即便知足以上條件也未必必定會回收, Hotspot VM還提供了
-Xnoclassgc
參數控制(關閉CLASS的垃圾回收功能).
附:HotSpot虛擬機在1.8以後已經取消了永久代,改成元空間,類的元信息被存儲在元空間中,元空間這裏不過多介紹,有興趣的同窗能夠本身瞭解下。
到此關於Java GC的基本概念、JVM的內存結構、GC回收基本機制都已經介紹的差很少了。有疑問或者發現文章中有錯誤的能夠在下方留言交流。像Java垃圾收集器、元空間這裏並無詳細的說明,以後有時間的話會單獨拿出來聊聊。