垃圾回收機制,Java很是重要的特性之一,它讓開發者無需關注空間的建立和釋放,而是以守護進程的形式在後臺自動回收垃圾。算法
堆,是在JVM啓動時建立的,屬於JVM運行時數據區的重要組成部分,主要用來維護運行時數據,如運行過程當中建立的實例對象和數據。若是動態建立的對象沒有獲得及時回收,持續堆積,最後會致使堆空間被佔滿,形成內存溢出。設計
Java提供的垃圾回收機制,在後臺建立一個守護進程。在內存緊張時自動執行垃圾回收,從而保證程序的正常運行。對象
所謂「垃圾」,指全部再也不存活的對象。進程
常見判斷對象是否存活的兩種方法:圖片
實際上,Java裏沒有采用這樣的方案來斷定對象的「存活性」。內存
參考下圖,object五、object六、object7爲不可達對象,視爲「垃圾」,會被垃圾回收器回收 開發
GC Roots自己必定是可達的,從他們出發遍歷到的對象才能保證必定可達。 Java裏存在如下四種必定可達對象:虛擬機
備註:下述圖中,黑色表明垃圾對象,灰色表明存活對象,綠色表明空白空間。it
第一步,標記,利用可達性遍歷堆內存時,把存活對象和垃圾對象進行標記(以下圖所示) io
第二步,清理,把標記爲垃圾對象進行清空,釋放所佔空間
總結,該方案簡單方便,但容易產生內存碎片。
基於標記-清理方案,在清理時將全部存活的對象集中到一塊兒,造成一個連續使用的內存空間,以下圖所示:
總結,標記-清理、標記-整理兩種方案,適合存活對象多、垃圾少的狀況,只須要清理較少的垃圾,挪動一下存活對象就能夠了。
這種比較粗暴,將堆內存一分爲二成兩部分,一段時間內只容許在其中一塊內存上進行分配,當該內存塊被分配完後,則執行垃圾回收:把全部存活對象複製到另外一塊內存裏,而後直接清空當前內存。
總結,這種作法不易產生碎片,簡單粗暴;可是,它只容許一段時間內只能使用一部份內存,超過這部份內存的話就有頻繁的複製清空。這種方案適合存活對象少、垃圾多的狀況,在複製只需移動少許的存活對象。
上述講到三種內存回收方案,那Java中是如何選擇利用這三種回收算法呢?
Java 堆空間(Heap)分紅三部分,這三部分存儲三類數據:
總結,常規的Java堆至少包括了新生代和老年代兩塊內存區域:
對於新生代區域,因爲每次GC都會有大量新對象死去,存活的較少。所以採用複製回收機制,GC時只把少數存活的對象複製過去便可。
複製算法設計:
缺陷:至關於只有一半的內存可用,對於新生代而言,新對象會頻繁地進行建立,若是隻有一半的可用內存,會持續 不斷地進行垃圾回收工做,影響了程序的正常運行。
最開始使用9的內存,當9快滿時執行復制回收機制,把9中存活的對象複製到1區,並清空9區。
缺陷:因爲內存空間比例相差較大,當把9區存活的對象複製到1區時,頗有可能1區放不下,此時不得不把對象移到老年區。這就意味着,可能會有一部分並不老的9區對象因爲1區放不下而被放到老年區,破壞了老年區的規則。
工做原理:
老年代通常存放存活時間較久的對象,因此每次GC時,存活對象多,每次只要少數對象被回收。所以,根據不一樣回收機制的特色,這裏選擇標記整理回收機制,僅僅經過少許地移動對象就能清理垃圾,並且不存在內存碎片。