垃圾回收(GC)是JVM的一大殺器,它使程序員能夠更高效地專一於程序的開發設計,而不用過多地考慮對象的建立銷燬等操做。可是這並非說程序員不須要了解GC。GC只是Java編程中一項自動化工具,任何一個工具都有它適用的範圍,當超出它的範圍的時候,可能它將不是那麼自動,而是須要人工去了解與適應地適用。程序員
擁有必定工做年限的程序員,在工做期間確定會常常碰到像內存溢出、內存泄露、高併發的場景。這時候在應對這些問題或場景時,若是對GC不瞭解,極可能會成爲我的的發展瓶頸。算法
接下來的兩文將詳細學習下JVM中垃圾回收(GC)的各個知識要點。本文先從GC的算法開始先了解,鋪墊好基礎,下一篇再詳細講JVM具體的GC實現。編程
垃圾回收,第一件事就是要搞清楚哪些東西是垃圾,然後才能對這些垃圾進行回收。微信
那麼有什麼辦法識別對象是否爲無用的垃圾呢?狹義地,怎麼判斷對象是否沒被引用呢?併發
一般有如下兩種算法去識別判斷編程語言
這個算法很是簡單。給對象一個計數器,每當這個對象被引用了,計數器值加一;引用失效,則減一。但這個對象計數值爲0的時候,證實是無用對象,能夠被GC程序回收掉。這種算法比較普遍應用在一些腳本語言上,如FLASH、PYTHON等。
可是引用計數算法沒法解決對象間相互引用的問題。當a對象引用了b對象,b對象也引用了a對象,這樣a、b兩個對象的計數器值都不會爲0,即便這兩個對象都被其餘對象所引用,最終致使這些對象一直沒法被回收。這種狀況每每會出如今比較複雜的編程語言中。
高併發
可達性分析算法(GC roots算法),普遍應用於主流的商用語言。設置一個根節點,從圖論角度來看,只要從該節點可達一個對象,證實這個對象是存活的(被引用)。
工具
一般地,GC會包含如下區域的對象:性能
瞭解完垃圾是怎麼找出來後,接下來看看它們是怎麼被清除的。如下介紹幾種清除的算法。學習
標記-清除,顧名思義,先標記垃圾,再清除。它是GC最基礎的算法,後續不少算法都是基於它上面去改進的。
標記的過程在上面搜索GC對象已經介紹過了。被標記的對象,在統一GC的時候會把標記的對象清除掉。這個算法比較簡單,不作過多贅述。
這個算法有一個很明顯的缺點,就是在垃圾回收後會產生大量不連續的碎片空間,致使程序要申請較大的對象時常沒法找到合適的內存空間,迫使再次GC。
複製算法的存在,正是爲了解決內存碎片問題。而且這個算法也是分代算法的基礎。
將內存分爲大小相等的兩塊,每次程序只使用其中一塊,當GC發生的時候,把存活的對象複製到另一塊內存中,整齊的排列,而後清空原來的那塊內存。
能夠看到,這種算法有點新生代轉移到老年代的感受。
缺點:
這種缺點,在老年代中,對象存活率比較高的場景下是很是場景間。
針對複製算法的兩個缺點,在老年代通常會用這種標記-整理算法。
把存活的對象移到內存的一段,而後把剩餘的空間所有清空掉。
分代算法並非一個特定的算法,也沒有什麼新的內容。而是把內存分紅多個區域,通常爲新生代、老年代等。而後根據不一樣區域不一樣的特色,用不一樣回收算法去回收垃圾。
例如新生代,對象存活率低,比較適用複製算法。老年代存活率高,比較適用Mark-Compact算法。
目前幾乎全部的商業虛擬機都是採用分代收集的。具體不一樣的收集器在下一文再詳細說明。
更多技術文章、精彩乾貨,請關注
博客:zackku.com
微信公衆號:Zack說碼