JVM中的垃圾回收器及垃圾收集算法描述

首先須要瞭解下JVM(Java虛擬機)中的內存分配狀況:java

 

收集器的介紹算法

Serial收集器:是最原始的收集器,是單線程的,實現簡單,可是在後臺收集垃圾的時候,其餘的工做線程都會中止,直到垃圾收集線程執行完畢,給用戶的體驗就是出現停頓現象,體驗差。可是當收集的垃圾少,停頓時間短,次數少,仍是能夠接受的。運行在Client模式下是一個很好的選擇。
ParNew收集器:是Serial收集器的多線程辦,不過在單處理器下效果不比Serial收集器效果好,多線程會採起對應的機制,默認開始的線程數量和CPU的數量相同。
CMS收集器:目標是縮短用戶的停頓時間,即垃圾收集的時間,是併發收集器,是犧牲吞吐量和新生代空間來換取的。
Parallel Scavenge收集器:目標是達到一個可控的吞吐量(運行用戶代碼/(運行用戶代碼+垃圾收集時間)),被稱爲吞吐量優先的收集器。採用複製算法實現多線程

 

算法併發

引用計數法:在對象中添加一個基數器,當有變量引用這個對象時,計數器就加一,當變量放開對這個對象的引用時,計數器就減一,當計數器的值爲0時,表示沒有引用這個對象的變量了,後續就能夠被垃圾收集器處理了。
優缺點:實現簡單,但針對互相引用的對象沒辦法進行清理。如:      objA.instance=objB;objB.instance=objA;這種狀況下,其餘變量引用這2個對象了,可是這兩個   對象仍然不能刪除,由於它們互相引用,計數器的值不爲0.測試

可達性分析:以GC Roots爲起點,從這些節點開始,向下搜索造成引用鏈,當GC Roots到某個對象爲不可達時,表示這個對象就是一個無用的對象,能夠在垃圾收集時進行處理。
標記-清處算法:進行2個過程,標記:把須要清理的對象都標記出來;清除:就是把標記的對象都清楚掉。這2個過程效率都不是很高,且會產生不少空間碎片,致使由於大對象沒有連續的內存分配空間而引發再次的垃圾回收。spa

複製算法:標記-清除算法中存在效率和空間碎片問題,此複製算法能夠解決效率問題,把內存空間分爲等同大小的塊,使用其中的一塊進程分配,當內存用完時,把還存活的對象放到另外一個內存中,而後把原理內存塊一塊兒清理掉,新塊中根據指針按需分配排列。實現簡單,效率好,可是會浪費通常的內存。
標記整理算法:此算法也是分爲2步,第一步標記,第二步整理,標記和前面講的標記同樣,僅是第二步整理,是把存活的對象往一個方向移動,而後清除掉邊緣部分。此種算法沒有空間碎片的存在了。
分代收集算法:沒有采用新的算法,而是根據對象的存活時間不一樣,把內存分爲新生代和老年代,且因爲新生代多爲新建立的對象,須要的內存空間大,比例按照8:1:1進行劃份內存的。而後根據區域的不一樣採用不一樣的收集算法,新生代的對象存活率低,可使用複製算法,老年代的對象存活率高,能夠採用標記清除或者標記整理算法。線程

 

GC日誌指針

GC的日誌格式就是時間+類型+內存數據等信息的構成
在日誌結果中,能夠觀察到,使用的收集器是Parallel Scavenge收集器-> PSYoungGen,ps是縮寫,默認的Default New Generation的是新生代是使用Serial收集器。名字與收集器有關。使用時根據具體的狀況進行實例對象的分配,好比新生代中的Eden區內存不夠時,接下來大的實例化對象存到survivor中也不夠,則就會直接存儲到老年區。日誌

而使用Serial收集器時,先分配6M的新生代區域,後面的4M不夠分配,會發生minor GC,在GC期間,6M的空間不足以分配到survivor區域(這個區域僅1M),因此會經過擔保機制把6M的對象直接放入到老年區。使用的收集器不一樣得出的垃圾回收日誌會不相同。
Minor GC:是指新生代的垃圾回收,通常java對象的生命週期都很短,minor GC頻繁,回收也快。
Full GC:指老年代的回收,常常會伴隨一次minor GC,但不是絕對的,Parallel Scavenge就能夠直接Major GC,速度通常比minor GC 慢10倍以上。code

測試代碼以下所示:

package com.class01;

/**
 * @Author: guopengxia
 * @Date: 2019/3/22 19:09
 * @Version: 1.0
 */
public class Class01 {
    private static final int _1MB=1024*1024;
    /**
     * 設置VM的參數:
     *   -Xms20M  -Xmx20M  -Xmn10M    //Xms,Xmx設置堆內存的大小(20M) Xmn:設置年輕代大小
     *   -XX:PrintGCDetails   //設置打印GC的詳細信息(收集器日誌參數)
     *   -XX:SurvivorRatio=8  //設置老年區的比例信息,新生區Eden:其中一個Survivor的比例爲8:1
     */

    public static void testAllocation(){
        byte [] allocation1,allocation2,allocation3,allocation4;
        allocation1=new byte[2*_1MB];
        allocation2=new byte[2*_1MB];
        allocation3=new byte[2*_1MB];
        allocation4=new byte[4*_1MB];  //此處會出現一次Minor GC(當新生代沒有內存進行分配時,會出現Minor GC)
    }

    public static void main(String []args){
        Class01.testAllocation();
    }
}

下面是日誌截圖,此次是日誌顯示到控制檯(能夠把GC的信息打印到日誌文件中,進行參數設置便可)

相關文章
相關標籤/搜索