垃圾收集器和內存分配側策略java
不少人會有疑問,爲何垃圾收集的機制已經實現了自動化,咱們還須要去了解GC和內存分配的麼?因爲堆裏面放着Java對象的實例,在垃圾收集器對堆進行回收以前,首先就要肯定這些對象還有哪些活着,而哪些已經死去。算法
package com.GC; public class ReferenceCountingGC { public Object instance = null; private static final int _1MB = 1024*1024; private byte[] bigsize = new byte[2*_1MB]; public static void main(String[] args) { ReferenceCountingGC a = new ReferenceCountingGC(); ReferenceCountingGC b = new ReferenceCountingGC(); a.instance = a; b.instance = b; a = null; b = null; System.gc(); } }
2.根搜索算法編程
在主流的編程語言中都是使用根搜索算法進行判斷對象是否存活。併發
基本思路:經過一系列名爲「GC Roots」的對象做爲起點,從這些節點開始向下搜索,搜索到的路徑稱爲引用鏈(Reference Chain),當一個對象到「GC Roots」不可到達的時候,說明該對象是不可用的,它就會被認爲是可回收的對象。編程語言
Java中,能夠做爲「GC Roots」對象包括一下幾種:高併發
1.虛擬機棧中引用的對象學習
2.方法區類靜態屬性引用的對象spa
3.方法區的常量引用的對象指針
4.本地方法棧中JNI的引用對象code
3.關於引用
在JDK1.2以後。對引用的概念進行了改進和擴從,並將應用分爲四類:強引用,軟引用,弱引用,虛引用。
強引用:在程序代碼中普便存在,就相似於new出來的對象,他們永遠都不會被垃圾收集器回收
軟引用:用來描述一些有用,但非必須的對象,對於這種對象,在系統發生內存異常以前,會把這些對象列進殼回收的範圍,進行第二次的回收,在內存仍是不充足的時候,纔會拋出異常。
弱引用:描述非必須的對象,強度比軟引用更弱一些,只能存活到下一次垃圾收集發生以前。
虛引用:咱們沒法經過虛引用獲取一個對象的實例,爲一個對象設置虛引用關聯的目的就是但願這個對象被垃圾收集器收集的時候收到一個系統的通知。
回收方法區
永久代的垃圾回收有兩部分的內容:廢棄常量和無用的類
回收常量和Java堆的回收差很少
如何判斷無用的類?
1.該類的全部實例都已經被回收
2.加載該類的類加載器已經被回收
3.該類的Class對象沒有被任何地方被引用,沒法經過在任何地方經過反射訪問該類。
垃圾回收算法
標記-清楚算法
做爲最基礎的收集算法,他的實現原理和它的名字同樣,分爲標記和清楚階段
缺點:效率的問題,標記和清楚的過程的效率都不高,在清除完以後,會產生大量的不連續的內存碎片,空間的碎片太多,當須要分配大對象的時候,就不得不提早觸發另外一次的垃圾回收。
複製算法
它的出現爲了解決效率的問題
原理:它將可用的內存分爲了兩份,每次只使用一份,當這一塊的內存用完了以後,就將還活着的對象複製到另外一塊去,而後把內存一次清理掉,然而就不用在繼續考慮內存碎片的問題了,只要移動堆頂的指針
缺點:它的代價爲內存爲原來的一半
也能夠將其分爲三部份,兩塊survivor較小和一塊較大eden,當回收的時候,將eden和survivor一次性的拷貝到另一塊的survivor上。
標記-整理算法
複製算法在對象的存貨率高的時候,就要複製大量的對象,效率就會很低,更重要的是還會浪費50%的內容
和該名字同樣,在最後的時候並非對對象直接清理,而是將存活的對象移向一段,清理邊界之外的內存
分代收集算法
該算法就是將對象的生存週期分爲幾塊,也就是吧Java的堆分爲新生代和老年代,更具不一樣代的特性去分配適當的垃圾收集算法
在新生代中,每次垃圾收集就會有大量的對象死去,因此適合用複製算法。老年代中,對象的存活率很高,因此能夠使用「標記-整理」或者「標記-清理」算法回收
《深刻理解Java虛擬機》的學習筆記