必知必會JVM垃圾回收——對象搜索算法與回收算法

垃圾回收(GC)是JVM的一大殺器,它使程序員可以更高效地專注於程序的開發設計,而不用過多地考慮對象的創建銷燬等操作。但是這並不是說程序員不需要了解GC。GC只是Java編程中一項自動化工具,任何一個工具都有它適用的範圍,當超出它的範圍的時候,可能它將不是那麼自動,而是需要人工去了解與適應地適用。

擁有一定工作年限的程序員,在工作期間肯定會經常碰到像內存溢出、內存泄露、高併發的場景。這時候在應對這些問題或場景時,如果對GC不瞭解,很可能會成爲個人的發展瓶頸。

接下來的兩文將詳細學習下JVM中垃圾回收(GC)的各個知識要點。本文先從GC的算法開始先了解,鋪墊好基礎,下一篇再詳細講JVM具體的GC實現。

GC對象搜索算法

垃圾回收,第一件事就是要搞清楚哪些東西是垃圾,而後才能對這些垃圾進行回收。

那麼有什麼辦法識別對象是否爲無用的垃圾呢?狹義地,怎麼判斷對象是否沒被引用呢?

通常有以下兩種算法去識別判斷<!--more-->

  • 引用計數算法
    這個算法非常簡單。給對象一個計數器,每當這個對象被引用了,計數器值加一;引用失效,則減一。但這個對象計數值爲0的時候,證明是無用對象,可以被GC程序回收掉。這種算法比較廣泛應用在一些腳本語言上,如FLASH、PYTHON等。
    但是引用計數算法無法解決對象間相互引用的問題。當a對象引用了b對象,b對象也引用了a對象,這樣a、b兩個對象的計數器值都不會爲0,即使這兩個對象都被其他對象所引用,最終導致這些對象一直無法被回收。這種情況往往會出現在比較複雜的編程語言中。
    必知必會JVM垃圾回收——對象搜索算法與回收算法

  • 可達性分析算法
    可達性分析算法(GC roots算法),廣泛應用於主流的商用語言。設置一個根節點,從圖論角度來看,只要從該節點可達一個對象,證明這個對象是存活的(被引用)。
    必知必會JVM垃圾回收——對象搜索算法與回收算法

通常地,GC會包含以下區域的對象:

  • 虛擬機棧(棧幀中的本地變量表)中引用的對象;
  • 方法區中類靜態屬性引用的對象;
  • 方法區中常量引用的對象;
  • 本地方法棧中JNI(即一般說的Native方法)引用的對象;

垃圾回收算法

瞭解完垃圾是怎麼找出來後,接下來看看它們是怎麼被清除的。以下介紹幾種清除的算法。

標記-清除算法(Mark-Sweep)

標記-清除,顧名思義,先標記垃圾,再清除。它是GC最基礎的算法,後續很多算法都是基於它上面去改進的。
標記的過程在上面搜索GC對象已經介紹過了。被標記的對象,在統一GC的時候會把標記的對象清除掉。這個算法比較簡單,不做過多贅述。

必知必會JVM垃圾回收——對象搜索算法與回收算法
這個算法有一個很明顯的缺點,就是在垃圾回收後會產生大量不連續的碎片空間,導致程序要申請較大的對象時常無法找到合適的內存空間,迫使再次GC。

複製算法

複製算法的存在,正是爲了解決內存碎片問題。並且這個算法也是分代算法的基礎。

將內存分爲大小相等的兩塊,每次程序只使用其中一塊,當GC發生的時候,把存活的對象複製到另外一塊內存中,整齊的排列,然後清空原來的那塊內存。
必知必會JVM垃圾回收——對象搜索算法與回收算法
可以看到,這種算法有點新生代轉移到老年代的感覺。

缺點:

  1. 把內存可使用的空間減少了一半,造成空間的浪費。
  2. 對象存活數量較多的時候,複製性能比較差

這種缺點,在老年代中,對象存活率比較高的場景下是非常場景間。

標記-整理算法(Mark-Compact)

針對複製算法的兩個缺點,在老年代一般會用這種標記-整理算法。

把存活的對象移到內存的一段,然後把剩餘的空間全部清空掉。
必知必會JVM垃圾回收——對象搜索算法與回收算法

分代收集算法---

title: 必知必會JVM垃圾回收——對象搜索算法與回收算法
categories:

  • JVM深入
    tags:
  • JVM
  • GC
    date: 2018-09-27 15:09:36

垃圾回收(GC)是JVM的一大殺器,它使程序員可以更高效地專注於程序的開發設計,而不用過多地考慮對象的創建銷燬等操作。但是這並不是說程序員不需要了解GC。GC只是Java編程中一項自動化工具,任何一個工具都有它適用的範圍,當超出它的範圍的時候,可能它將不是那麼自動,而是需要人工去了解與適應地適用。

擁有一定工作年限的程序員,在工作期間肯定會經常碰到像內存溢出、內存泄露、高併發的場景。這時候在應對這些問題或場景時,如果對GC不瞭解,很可能會成爲個人的發展瓶頸。

接下來的兩文將詳細學習下JVM中垃圾回收(GC)的各個知識要點。本文先從GC的算法開始先了解,鋪墊好基礎,下一篇再詳細講JVM具體的GC實現。

GC對象搜索算法

垃圾回收,第一件事就是要搞清楚哪些東西是垃圾,而後才能對這些垃圾進行回收。

那麼有什麼辦法識別對象是否爲無用的垃圾呢?狹義地,怎麼判斷對象是否沒被引用呢?

通常有以下兩種算法去識別判斷<!--more-->

  • 引用計數算法
    這個算法非常簡單。給對象一個計數器,每當這個對象被引用了,計數器值加一;引用失效,則減一。但這個對象計數值爲0的時候,證明是無用對象,可以被GC程序回收掉。這種算法比較廣泛應用在一些腳本語言上,如FLASH、PYTHON等。
    但是引用計數算法無法解決對象間相互引用的問題。當a對象引用了b對象,b對象也引用了a對象,這樣a、b兩個對象的計數器值都不會爲0,即使這兩個對象都被其他對象所引用,最終導致這些對象一直無法被回收。這種情況往往會出現在比較複雜的編程語言中。
    必知必會JVM垃圾回收——對象搜索算法與回收算法

  • 可達性分析算法
    可達性分析算法(GC roots算法),廣泛應用於主流的商用語言。設置一個根節點,從圖論角度來看,只要從該節點可達一個對象,證明這個對象是存活的(被引用)。
    必知必會JVM垃圾回收——對象搜索算法與回收算法

通常地,GC會包含以下區域的對象:

  • 虛擬機棧(棧幀中的本地變量表)中引用的對象;
  • 方法區中類靜態屬性引用的對象;
  • 方法區中常量引用的對象;
  • 本地方法棧中JNI(即一般說的Native方法)引用的對象;

垃圾回收算法

瞭解完垃圾是怎麼找出來後,接下來看看它們是怎麼被清除的。以下介紹幾種清除的算法。

標記-清除算法(Mark-Sweep)

標記-清除,顧名思義,先標記垃圾,再清除。它是GC最基礎的算法,後續很多算法都是基於它上面去改進的。
標記的過程在上面搜索GC對象已經介紹過了。被標記的對象,在統一GC的時候會把標記的對象清除掉。這個算法比較簡單,不做過多贅述。

必知必會JVM垃圾回收——對象搜索算法與回收算法
這個算法有一個很明顯的缺點,就是在垃圾回收後會產生大量不連續的碎片空間,導致程序要申請較大的對象時常無法找到合適的內存空間,迫使再次GC。

複製算法

複製算法的存在,正是爲了解決內存碎片問題。並且這個算法也是分代算法的基礎。

將內存分爲大小相等的兩塊,每次程序只使用其中一塊,當GC發生的時候,把存活的對象複製到另外一塊內存中,整齊的排列,然後清空原來的那塊內存。
必知必會JVM垃圾回收——對象搜索算法與回收算法
可以看到,這種算法有點新生代轉移到老年代的感覺。

缺點:

  1. 把內存可使用的空間減少了一半,造成空間的浪費。
  2. 對象存活數量較多的時候,複製性能比較差

這種缺點,在老年代中,對象存活率比較高的場景下是非常場景間。

標記-整理算法(Mark-Compact)

針對複製算法的兩個缺點,在老年代一般會用這種標記-整理算法。

把存活的對象移到內存的一段,然後把剩餘的空間全部清空掉。
必知必會JVM垃圾回收——對象搜索算法與回收算法

分代收集算法

分代算法並不是一個特定的算法,也沒有什麼新的內容。而是把內存分成多個區域,一般爲新生代、老年代等。然後根據不同區域不同的特點,用不同回收算法去回收垃圾。

例如新生代,對象存活率低,比較適用複製算法。老年代存活率高,比較適用Mark-Compact算法。

目前幾乎所有的商業虛擬機都是採用分代收集的。具體不同的收集器在下一文再詳細說明。


更多技術文章、精彩乾貨,請關注
博客:zackku.com
微信公衆號:Zack說碼
必知必會JVM垃圾回收——對象搜索算法與回收算法
分代算法並不是一個特定的算法,也沒有什麼新的內容。而是把內存分成多個區域,一般爲新生代、老年代等。然後根據不同區域不同的特點,用不同回收算法去回收垃圾。

例如新生代,對象存活率低,比較適用複製算法。老年代存活率高,比較適用Mark-Compact算法。

目前幾乎所有的商業虛擬機都是採用分代收集的。具體不同的收集器在下一文再詳細說明。


更多技術文章、精彩乾貨,請關注
博客:zackku.com
微信公衆號:Zack說碼
必知必會JVM垃圾回收——對象搜索算法與回收算法

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章