Java垃圾收集學習筆記

(1)除了釋放不再被引用的對象,垃圾收集器還要處理堆碎塊。請求分配新對象時可能不得不增大堆空間的大小,雖然可以使用的空閒空間是足夠的,但是堆中沒有沒有連續的空間放得下新對象。可能會導致虛擬機產生不必要的”內存不足“錯誤。

(2)使用垃圾收集堆,有一個潛在的缺陷就是加大程序的負擔,可能影響程序的性能。因爲虛擬機需要追蹤哪些對象被正在執行的程序引用,還要動態釋放垃圾對象。

(3)程序可以調用System.gc()建議jvm去收集垃圾, 但是不能爲垃圾回收機制指定某個對象是不是垃圾。即便調用了gc()並不會馬上進行垃圾回收甚至不一定會執行垃圾回收。所有的內存分配和回收權限都在jvm,不在開發人員手裏。

可以試試:

public class RubbishRelease {
    // 類的finalize方法,可以告訴垃圾回收器應該執行的操作,該方法從Object類繼承而來。
    // 在從堆中永久刪除對象之前,垃圾回收器調用該對象的finalize方法。
    public void finalize() {
        System.out.println("the Object is going...");
    }

    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            // 下面不斷創建對象,但是這些對象都沒有被引用
            new RubbishRelease();
            new RubbishRelease();
            new RubbishRelease();
            System.gc();
        }
        System.out.println("The program is over!");
    }
}

運行結果:

這裏寫圖片描述

(4)垃圾收集算法有很多,但任何垃圾收集算法都必須做兩件事情。首先,它必須檢測出垃圾對象。其次,它必須回收垃圾對象所使用的堆空間並還給程序

(5)區分活動對象和垃圾的兩個基本方法是引用計數跟蹤

(6)引用計數是垃圾收集的早期策略。在這種方法中,堆中每一個對象都有一個引用計數。一個對象被創建了,並且指向該對象的引用被分配給一個變量,這個對象的引用計數被置爲1。當任何其他變量被賦值爲對這個對象的引用時,計數加1。當一個對象的引用超過了生存期或者被設置一個新的值時,對象的引用計數減1。任何引用計數爲0的對象可以被當作垃圾收集。當一個對象被垃圾收集的時候,它引用的任何對象計數值減1。這種方法的好處是,引用計數收集器可以很快地執行,交織在程序的運行之中。這個特性對於程序不能被長時間打斷的實時環境很有利。壞處就是,引用計數無法檢測出循環(即兩個或者更多的對象互相引用)。

(7)跟蹤收集器追蹤從根節點開始的對象引用圖。給追蹤過程中遇到對象以某種方式打上標記。追蹤結束時,未被標記的對象就是無法觸及的,從而被收集。基本的追蹤算法被稱作“標記並清除”,這個名字指出垃圾收集過程的兩個階段。

(8)Java虛擬機的垃圾收集器可能有對付堆碎塊的策略。標記並清除收集器通常使用的兩種策略是壓縮拷貝。這兩種方法都是快速地移動對象來減少堆碎塊。

(9)壓縮收集器把活動的對象越過空閒區滑動到堆的一端,在這個過程中,堆的另一端出現一個大的連續空閒區。所有被移動的對象的引用也被更新,指向新的位置。

(10)拷貝收集器把所有的活動的對象移動到一個新的區域。在拷貝過程中,被緊挨着佈置,這樣可以消除原本它們在舊區域的空隙。即空閒區。一般的拷貝收集器算法被稱爲“停止並拷貝”。此方案中,堆被分成兩個區域,任何時候都使用一個區域。對象在同一個區域中分配直到被耗盡。此時,程序執行被中止,堆被遍歷,遍歷時遇到活動的對象被拷貝到另個區域。當停止和拷貝過程結束時,程序恢復執行。依次往復,對於指定大小的堆來說需要兩倍大小的內存,由於任何時候都只使用其中的一半,這就是該方法帶來的代價。

(11)按代收集:根據對象的存活週期(一次垃圾收集爲一個週期)的不同將內存劃分爲幾塊。一般是把Java堆分爲新生代和老年代,這樣就可以根據各個年代的特點採用最適當的收集算法。在新生代中,每次垃圾收集時都發現有大批對象死去,只有少量存活,那就選用拷貝算法,只需要付出少量存活對象的拷貝成本就可以完成收集。而老年代中因爲對象存活率高、沒有額外空間對它進行分配擔保,可以使用“標記並清除”算法。

(12)終結方法(finalize),這個在上面第3點也有提到:這個方法是垃圾收集器在釋放對象前必須運行。這個可能存在的終結方法使得任何Java虛擬機的垃圾收集器要完成的工作更加複雜。因爲終結方法可能“復活”了某些不再被引用的對象(本身或者其他對象)。

(13)中的每一個對象都有三種狀態之一:可觸及的可復活的以及不可觸及的可觸及狀態好理解。關於可復活狀態:它在從根節點開始的追蹤圖中不可觸及,但是又可能在垃圾收集器執行某些終結方法時觸及。不僅僅是那些聲明瞭finalize方法的對象,而是所有的對象都要經過可復活狀態。而不可觸及狀態標誌着不但對象不再被觸及,而且也不可能通過任何終結方法復活。不可觸及的對象不再對程序的執行產生影響,可自由地回收它們佔據的內存。

(14)對象的強,軟,弱,虛引用。

強引用:如果一個對象具有強引用,垃圾回收器絕不會回收它。當內存空間不足,JVM寧願拋出OutOfMemoryError錯誤,使程序異常終止,也不會考隨意回收具有強引用的對象來解決內存不足的問題。

軟引用:如果一個對象具有軟引用。如果內存空間足夠。垃圾回收器不會回收它。如果內存不足了,就會回收這些對象的內存。只要垃圾回收器沒有回收它,該對象就可以被程序使用。軟引用可用來實現內存敏感的高速緩存。

弱引用:如果一個對象具有弱引用。當垃圾回收器發現只具有弱引用對象,不管當前內存空間足夠與否,都會回收它的內存。不過,由於垃圾回收器是一個優先級很低的線程,因此不一定會很快發現只具有弱引用的對象。

虛引用:虛引用不會決定對象的生命週期。如果一個對象僅持有虛引用,那麼它就和沒有任何引用一樣,在任何時候都可能被垃圾回收器回收。

發佈了98 篇原創文章 · 獲贊 1338 · 訪問量 177萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章