JAVA虛擬機

垃圾回收主要是回收堆內存。在垃圾回收期(GC)回收之前,需要確定哪些對象可以回收,有以下幾種方法:

  1. 引用計數算法 
    原理:給對象添加一個引用計數器,每當有一個地方引用它時,計數器值就加1;當引用失效時,計數器值就減1;任何時刻計數器都爲0的對象就是不可能再被使用的。這種算法效率高。不過很難解決對象之間的相互循環引用的問題。

  2. 根搜索算法(默認) 
    原理:通過一系列的名爲“GC Roots”的對象作爲起始點,從這些節點開始向下搜索,搜索所走過的路徑稱爲引用鏈,當一個對象到GC Roots沒有任何引用鏈相連時,則證明此對象是不可用的。作爲GC Roots的對象包括以下幾種:

  • 虛擬機棧中的引用的對象

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

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

  • 本地方法棧中JNI的引用的對象

引用

  • 強引用,類似"Object obj = new Object()"這種,只要強引用存在,則GC永遠不會回收被引用的對象

  • 軟引用,指還有用,但是並非必須的對象,內存溢出之前進行回收,實現軟引用可以通過SoftReference類,軟引用主要用戶實現類似緩存的功能,在內存足夠的情況下直接通過軟引用取值,無需從繁忙的真實來源查詢數據,提升速度;當內存不足時,自動刪除這部分緩存數據,從真正的來源查詢這些數據。

  • 弱引用,跟軟引用一樣,不過強度比軟引用弱一些,第二次垃圾回收時回收,實現弱引用可以通過WeakReference類,弱引用主要用於監控對象是否已經被垃圾回收器標記爲即將回收的垃圾,可以通過弱引用的isEnQueued方法返回對象是否被垃圾回收器標記。

  • 虛引用,是最弱的一種引用關係,垃圾回收時回收,無法通過引用取到對象值。主要用於檢測對象是否已經從內存中刪除。

垃圾收集算法

  1. 標記-清除算法:首先標記出所有需要回收的對象,在標記完成後統一回收所有被標記的對象,不過該算法有以下缺點:

  • 效率低

  • 空間問題,該算法會產生大量不連續的內存碎片,這樣導致程序在以後的運行中如果需要分配較大對象時無法找到足夠的連續內存而觸發另一次垃圾收集動作

複製算法:將可用內存按容量劃分大小相等的兩塊,每次只使用其中的一塊。當一塊內存用完了,就將還存活的對象複製到另外一塊上面,然後再把已使用過的內存空間一次清理掉。這種算法實現簡單,效率高,不過會將可使用的內存減少一半。如果對象存活率高就要執行較多的複製操作,將導致效率變低。目前在複製算法中,通常是將內存分爲一塊較大的Eden空間和兩塊較小的Survivor空間,每次只使用Eden和一塊Survivor。當回收時,將Eden和Survivor中還存活的對象一次性拷貝到另外一塊Survivor中,最後清理使用的Eden和Survivor。並且以老年代作爲空間分配擔保,即Survivor無法容納的對象會直接進入老年代。目前新生代主要採用這個算法。

標記-整理算法:將所有存活的對象都向一端移動,然後直接清理掉邊界以外的內存。

分代收集算法:根據對象的存活週期的不同將內存劃分爲幾塊,一般是分爲新生代和老年代。然後根據各個年代的特點採用最適當的收集算法。新生代通常採用複製算法,因爲對象生存時間都不長。老年代一般採用"標記-清理"或者"標記-整理"算法回收,因爲老年代中對象存活率高,沒有額外空間對它進行分配擔保。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章