垃圾收集 Garbage Collection 一般被稱爲「GC」, 在jvm 中,<font color=red>程序計數器、虛擬機棧、本地方法棧都是隨線程而生隨線程而滅,棧幀隨着方法的進入和退出作入棧和出棧操做,實現了自動的內存清理,所以,咱們的內存垃圾回收主要集中於 java 堆和方法區中</font>,在程序運行期間,這部份內存的分配和使用都是動態的!html
@[toc]java
既然是垃圾回收,那確定要知道什麼是垃圾了是吧,我相信哪一天落魄java開發宜春小哥哥去撿垃圾維持生活,哈氣、一juo、彎腰、開蓋、倒水,一鼓作氣我閉着眼,把廣東靚仔沒喝完的快樂肥宅水錯當垃圾撿了,這廣東靚仔還不得打人?是的,而JVM的垃圾收集的前提就是明確啥是垃圾!JVM首先會進行一系列計數算法判斷是否是垃圾。在JVM認爲是不是垃圾的評判標準爲對象是否存活,對象存活就不是垃圾,不能進行回收,反之進行回收。算法
判斷對象是否存活的JVM兩種計數算法主要有兩種,分別是:引用計數、可達性分析計數算法。編程
一聽到計數算法中有「 算法 」二字,小白童鞋發愣了:媽呀,數學很差,完了,不學了...咳咳咳,咋們不提算法,從咋們的平常生活開始着手,在咱們平時一個東西常常沒被使用,並且也用不上什麼地方,那麼這個東西能夠說就是垃圾。其實在 Java 中也是如此,若是一個對象不可能再被引用,那麼這個對象就是垃圾,應該被回收。就是這麼簡單粗暴,JVM兩種計數算法就是這樣子的,真的不復雜。設計模式
根據咱們生活上的思想,咱們很容易想到使用引用計數的方法來判斷垃圾。在一個對象被引用時加一,被去除引用時減一,這樣咱們就能夠經過判斷引用計數是否爲0來判斷一個對象是否爲垃圾。這種方法咱們通常稱之爲「引用計數法」。確實賊簡單的一個思路也正是覺得它的簡單,從而存在缺陷,所以引用計數算法是這樣定義的併發
一、引用計數:每一個對象有一個引用計數屬性,新增一個引用時計數加1,引用釋放時計數減1,計數爲0時能夠回收。 二、正因方法簡單,<font color=red>從而引用計數算法沒法解決對象相互循環引用的問題</font>。jvm
小白童鞋可能不知道啥是對象循環引用,熊dei看圖 學習
首先聲明一點:在實際開發語言好比java、C#等都是採用可達性分析計數算法判斷對象是否存活!優化
可達性分析算法的定義以下:spa
可達性分析(Reachability Analysis):從
GC Roots
開始向下搜索,搜索所走過的路徑稱爲引用鏈。當一個對象到GC Roots沒有任何引用鏈相連時,則證實此對象是不可用的。不可達對象。
相信很容易看出,其實都很好理解,惟獨GC Roots有點抽象,那啥是GC Roots呢?在Java語言中,<font color=red>GC Roots</font>主要包括:
一、對象的引用,位於虛擬機棧中。 二、方法區中的靜態引用。 三、本地方法棧中JNI的引用。【JNI通常指的是Native方法】 簡單地說,GC Root 就是通過精心挑選的一些引用
像上面的循環引用的這種狀況引用計數算法是沒法進行GC掉的,而根搜索算法能夠作到,所以引用計數算法存在缺陷!根搜索算法更好!
以上內容概述了啥垃圾,接下來就要講講如何進行回收垃圾!在生活中咱們收集垃圾,能夠一邊走一邊掃,也能夠把垃圾全都掃到一塊兒再一次清理。在JVM中,相似生活,提供了一系列的垃圾收集算法。
並且咱們還常常能看到垃圾分類,分紅可回收垃圾,和不可回收垃圾,可是從某一意義上來說,還都是垃圾,若是人人都遵照垃圾分類規則,我估計之後收破爛的大叔大媽都每天從可回收垃圾桶下手了,其實在JVM中也相似如此,JVM採起了分區、分代收集的思想。
常見的垃圾回算法:標記清除算法、複製算法、標記整理算法、分代收集算法。
標記清除算法。從名字能夠看到其分爲兩個階段:<font color=red>標記</font>階段和<font color=red>清除</font>階段。一種可行的實現方式是,在標記階段,標記全部由 GC Root 觸發的可達對象。此時,全部未被標記的對象就是垃圾對象。以後在清除階段,清除全部未被標記的對象。<font color=red>標記清除算法最大的問題就是空間碎片問題</font>。若是空間碎片過多,則會致使內存空間的不連續。雖然說大對象也能夠分配在不連續的空間中,可是效率要低於連續的內存空間。
複製(Copying)算法。複製算法的核心思想是將原有的內存空間劃分爲大小相等的兩塊,每次只使用一塊,在垃圾回收時,將正在使用的內存中的存活對象複製到未使用的內存塊中。以後清除正在使用的內存塊中的全部對象,以後交換兩個內存塊的角色,完成垃圾回收。<font color=red>複製算法的缺點是要將內存空間折半,極大地浪費了一半內存空間。</font>所以如今的商業虛擬機都使用這種複製算法來進行<font color=red>新生代</font>的垃圾收集!由於在對象存活率高的時候,複製算法就顯得效率低下
關於標記-整理算法還有一種叫法是標記壓縮算法,知道其說的同一者就行了。
標記整理算法。標記整理算法能夠說是標記清除算法的優化版,其一樣須要經歷兩個階段,分別是:標記階段、整理階段。在標記階段,從 GC Root 引用集合觸發去標記全部對象,和標記清除算法中的標記階段是同樣同樣的。在整理階段,其則是將全部存活的對象整理在內存的一邊,以後清理邊界外的全部空間。所以,<font color=red>標記-整理算法(Mark-Compact)不會產生內存碎片,可是會多花點時間用在整理(Compact)上面!</font>
「分代收集」(Generational Collection)算法,把Java堆分爲新生代和老年代,這樣就能夠根據各個年代的特色採用最適當的收集算法。在新生代中,每次垃圾收集時都發現有大批對象死去,只有少許存活,<font color=red>那新生代選用複製算法</font>,只須要付出少許存活對象的複製成本就能夠完成收集。而老年代中由於對象存活率高、沒有額外空間對它進行分配擔保,<font color=red>老年代就使用「標記-清理」或「標記-整理」算法來進行回收。</font>
標記清除算法
分爲<font color=red>標記</font>階段和<font color=red>清除</font>兩階段。<font color=red>標記清除算法最大的問題就是空間碎片問題</font>。比較適合在存活對象比較多的狀況。
複製算法(Copying)
<font color=red>複製算法的缺點是浪費了一半內存空間。</font>如今的商業虛擬機都使用這種複製算法來進行<font color=red>新生代</font>的垃圾收集!由於在對象存活率高的時候,複製算法就顯得效率低下比較適合存活對象比較少的狀況。
標記整理算法(Mark-Compact)
標記整理算法是標記清除算法的優化版,<font color=red>標記-整理算法(Mark-Compact)不會產生內存碎片,可是會多花點時間用在整理(Compact)上面!</font>
分代收集算法(Generational Collection)
<font color=red>新生代選用複製算法</font>,<font color=red>老年代使用「標記-清理」或「標記-整理」算法來進行回收。</font>
借用大佬整理的一張圖:
若是本文對你有一點點幫助,那麼請點個讚唄,謝謝~
最後,如有不足或者不正之處,歡迎指正批評,感激涕零!若是有疑問歡迎留言,絕對第一時間回覆!
歡迎各位關注個人公衆號,裏面有一些java學習資料和一大波java電子書籍,好比說周志明老師的深刻java虛擬機、java編程思想、核心技術卷、大話設計模式、java併發編程實戰.....都是java的聖經,不說了快上Tomcat車,咋們走!最主要的是一塊兒探討技術,嚮往技術,追求技術,說好了來了就是盆友喔...
原文出處:https://www.cnblogs.com/yichunguo/p/12012841.html