程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> JVM中的垃圾回收

JVM中的垃圾回收

編輯:關於C++

GC

垃圾回收回收什麼

Java的內存分配原理與C/C++不同,C/C++每次申請內存時都要malloc進行系統調用,而系統調用發生在內核空間,每次都要中斷進行切換,這需要一定的開銷.

而Java虛擬機是先一次性分配一塊較大的空間,然後每次new時都在該空間上進行分配和釋放,減少了系統調用的次數,節省了一定的開銷。節省開銷的同時,我們也必須對其進行垃圾的檢測和回收。

java一般內存申請有兩種:靜態內存和動態內存。很容易理解,編譯時就能夠確定的內存就是靜態內存,即內存是固定的,系統一次性分配,比如int類型變量;動態內存分配就是在程序執行時才知道要分配的存儲空間大小,比如java對象的內存空間。根據上面我們知道,java棧、程序計數器、本地方法棧都是線程私有的,線程生就生,線程滅就滅,棧中的棧幀隨著方法的結束也會撤銷,內存自然就跟著回收了。所以這幾個區域的內存分配與回收是確定的,我們不需要管的。但是java堆和方法區則不一樣,我們只有在程序運行期間才知道會創建哪些對象,所以這部分內存的分配和回收都是動態的。一般我們所說的垃圾回收也是針對的這一部分。

垃圾回收主要是針對堆空間和方法區的。

GC策略

垃圾檢測

垃圾檢測存在兩種策略,第一種是引用計數,第二種是可達性分析。

引用計數是給對象添加一個引用計數器,另外一個對象引用它,計數器自增,反之自減。但這樣的引用計數存在一定問題,若存在兩個對象A,B互相引用,而沒有外部對象引用它們。這時,這兩個垃圾對象不能被檢測出來。 可達性分析是以根集對象(棧中對象、方法區常量對象等)作為起點,向下搜索,如果不能搜索到的對象就是垃圾對象,可以進行回收。如果采用Dijkstra算法,其時間復雜對為O(m),m為對象個數。

垃圾回收

垃圾回收按照基本回收策略分有以下回收策略

按策略分類

引用計數:

對於引用計數來說,回收引用數為0的對象即可,但其存在致命缺陷即不能處理循環引用的問題

復制(copying):

此算法將內存分為兩個區域,內存的分配每次只使用其中一個區域(兩次gc之間)。回收時將標記為垃圾的對象清除,把標記為非垃圾的對象復制到另一個區域中。

\

此算法速度快,不會出現內存碎片,可並發實現。但是缺點也很明顯,即需要兩倍的內存空間。

標記-清除(Mark-Sweep):

對標記為垃圾的對象進行清除,不整理。

\vc8gPGNvZGU+seq8x9X7wO08L2NvZGU+ILe9t6i/7KOssrvAy7fRtu7N4rXExNq05r/VvOSjrL/J0tSyoreiyrXP1qGjtau74bL6yfrE2rTmy+nGrKOs0KfCyrK7uN+hozwvcD4NCjxoNSBpZD0="標記-整理mark-compact">標記-整理(Mark-Compact):

對標記為垃圾的對象進行清除,清除後進行整理,按順序存放。

\

此算法避免了復制標記清除的缺點,不浪費內存空間,同時不會產生內存碎片。但其速度是最慢的,且難以並發實現。

按系統線程分類

串行收集:

串行收集使用單線程處理所有垃圾回收工作,因為無需多線程交互,實現容易,而且效率比較高。但是,其局限性也比較明顯,即無法使用多處理器的優勢,所以此收集適合單處理器機器。當然,此收集器也可以用在小數據量(100M左右)情況下的多處理器機器上。

並行收集:

並行收集使用多線程處理垃圾回收工作,因而速度快,效率高。而且理論上CPU數目越多,越能體現出並行收集器的優勢。

並發收集:

相對於串行收集和並行收集而言,前面兩個在進行垃圾回收工作時,需要暫停整個運行環境,而只有垃圾回收程序在運行,因此,系統在垃圾回收時會有明顯的暫停,而且暫停時間會因為堆越大而越長。

JVM中的實際GC

JVM使用分代收集算法。分代的垃圾回收策略,是基於這樣一個事實:不同的對象的生命周期是不一樣的。因此,不同生命周期的對象可以采取不同的收集方式,以便提高回收效率。

為什麼要運用分代垃圾回收策略?在java程序運行的過程中,會產生大量的對象,因每個對象所能承擔的職責不同所具有的功能不同所以也有著不一樣的生命周期,有的對象生命周期較長,比如Http請求中的Session對象,線程,Socket連接等;有的對象生命周期較短,比如String對象,由於其不變類的特性,有的在使用一次後即可回收。

試想,在不進行對象存活時間區分的情況下,每次垃圾回收都是對整個堆空間進行回收,那麼消耗的時間相對會很長,而且對於存活時間較長的對象進行的掃描工作等都是徒勞。因此需要進行分層,不同生命存活時間的對象使用不同回收方法。

如何劃分?將對象按其生命周期的不同劃分成:年輕代(Young Generation)、年老代(Old Generation)、持久代(Permanent Generation)。其中持久代主要存放的是類信息,所以與java對象的回收關系不大,與回收息息相關的是年輕代和年老代。

\

上面有7中收集器,分為兩塊,上面為新生代收集器,下面是老年代收集器。如果兩個收集器之間存在連線,就說明它們可以搭配使用。

Serial(串行GC)收集器

Serial收集器是一個新生代收集器,單線程執行,使用復制算法。它在進行垃圾收集時,必須暫停其他所有的工作線程(用戶線程)。是Jvm client模式下默認的新生代收集器。對於限定單個CPU的環境來說,Serial收集器由於沒有線程交互的開銷,專心做垃圾收集自然可以獲得最高的單線程收集效率。

ParNew(並行GC)收集器

ParNew收集器其實就是serial收集器的多線程版本,除了使用多條線程進行垃圾收集之外,其余行為與Serial收集器一樣。

Parallel Scavenge(並行回收GC)收集器

Parallel Scavenge收集器也是一個新生代收集器,它也是使用復制算法的收集器,又是並行多線程收集器。parallel Scavenge收集器的特點是它的關注點與其他收集器不同,CMS等收集器的關注點是盡可能地縮短垃圾收集時用戶線程的停頓時間,而parallel Scavenge收集器的目標則是達到一個可控制的吞吐量。吞吐量= 程序運行時間/(程序運行時間 + 垃圾收集時間),虛擬機總共運行了100分鐘。其中垃圾收集花掉1分鐘,那吞吐量就是99%。

停頓時間越短就越適合需要與用戶交互的程序,良好的響應速度能提升用戶體驗,而高吞吐量則可以高效率地利用CPU時間,盡快完成程序的運算任務,主要適合在後台運算而不需要太多交互的任務。

並行回收GC通過調節內部參數(晉升老年代的年齡,回收間隔等)來控制吞吐量和速度。

Serial Old(串行GC)收集器

Serial Old是Serial收集器的老年代版本,它同樣使用一個單線程執行收集,使用“標記-整理”算法。主要使用在Client模式下的虛擬機。

Parallel Old(並行GC)收集器

Parallel Old是Parallel Scavenge收集器的老年代版本,使用多線程和“標記-整理”算法。

CMS(並發GC)收集器

CMS(Concurrent Mark Sweep)收集器是一種以獲取最短回收停頓時間為目標的收集器。CMS收集器是基於“標記-清除”算法實現的,整個收集過程大致分為4個步驟:

①.初始標記(CMS initial mark)

②.並發標記(CMS concurrenr mark)

③.重新標記(CMS remark)

④.並發清除(CMS concurrent sweep)

其中初始標記、重新標記這兩個步驟任然需要停頓其他用戶線程。初始標記僅僅只是標記出GC ROOTS能直接關聯到的對象,速度很快,並發標記階段是進行GC ROOTS 根搜索算法階段,會判定對象是否存活。而重新標記階段則是為了修正並發標記期間,因用戶程序繼續運行而導致標記產生變動的那一部分對象的標記記錄,這個階段的停頓時間會被初始標記階段稍長,但比並發標記階段要短。

由於整個過程中耗時最長的並發標記和並發清除過程中,收集器線程都可以與用戶線程一起工作,所以整體來說,CMS收集器的內存回收過程是與用戶線程一起並發執行的。

CMS收集器的優點:並發收集、低停頓,但是CMS還遠遠達不到完美,其主要有三個顯著缺點:

CMS收集器對CPU資源非常敏感。在並發階段,雖然不會導致用戶線程停頓,但是會占用CPU資源而導致引用程序變慢,總吞吐量下降。CMS默認啟動的回收線程數是:(CPU數量+3) / 4。

CMS收集器無法處理浮動垃圾(gc運行時產生的垃圾),可能出現“Concurrent Mode Failure“,失敗後而導致另一次Full GC(老生代GC)的產生。
最後一個缺點,由於采用標記清除方法,會產生大量碎片。空間碎片太多時,將會給對象分配帶來很多麻煩,比如說大對象,內存空間找不到連續的空間來分配不得不提前觸發一次Full GC。

G1收集器

G1(Garbage First)收集器是JDK1.7提供的一個新收集器,G1收集器基於“標記-整理”算法實現,也就是說不會產生內存碎片。還有一個特點之前的收集器進行收集的范圍都是整個新生代或老年代,而G1將整個Java堆(包括新生代,老年代)。

基於標記-整理算法,不產生內存碎片。

可以非常精確控制停頓時間,在不犧牲吞吐量前提下,實現低停頓垃圾回收。

G1收集器避免全區域垃圾收集,它把堆內存劃分為大小固定的幾個獨立區域,並且跟蹤這些區域的垃圾收集進度,同時在後台維護一個優先級列表,每次根據所允許的收集時間,優先回收垃圾最多的區域。
區域劃分和優先級區域回收機制,確保G1收集器可以在有限時間獲得最高的垃圾收集效率。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved