JVM:垃圾回收算法、垃圾回收器

垃圾回收算法

什麼是垃圾?爲何要回收?java

在java中,當一個對象沒有被任何指針指向的時候,他就成爲了一個垃圾,也就應該對其進行回收,若是不對其進行回收就會形成內存泄露,甚至是內存溢出。程序員

垃圾回收分爲兩個階段垃圾標記和垃圾回收。算法

垃圾標記

引用計算算法(java並未使用,不存在循環引用形成內存泄露)數據庫

對每個對象保存一個整型的引用計數器屬性,用於記錄對象被引用的狀況。當對象被任何一個對象引用就會對計數器加以,引用失效就減一,直到計數器爲0,就把該對象視爲垃圾,對其進行回收。網絡

該算法具備效率高,沒有回收延遲的特性,可是他卻增大了開銷,每次進行加減法也增大了時間複雜度,同時,他不能處理循環引用的問題。因此實際上java並未採用這樣的算法。多線程

可達性分析算法併發

以根對象集合爲起始點,按照從上到下的方式搜索根對象集合所鏈接的目標對象是否可達。內存中存活的對象都直接或者間接同根對象鏈接在一塊兒。不然,就認爲該對象應該被回收。jvm

那麼根元素集合包括哪些?ide

  • 虛擬機棧中引用的對象。性能

    • 例如,各個線程調用方法中使用到的參數,局部變量等。
  • 本地方法棧內引用的對象。

  • 方法區中靜態屬性引用的對象。

  • 方法區中常量引用的對象。

    • 字符串常量池中的引用。
  • 全部被同步鎖持有的對象。

  • java虛擬機內部的引用。

對象的finalization機制

一個對象在被回收以前會執行finalization()方法,來進行資源釋放等操做。

雖然對象的finalization機制聽起來很高大上,可是咱們平時好像歷來沒有用過,沒有用過就對了,由於這是給垃圾回收調用的,並不須要程序員調用,並且也不容許程序員調用。由於finalization可能會致使對象復活,其次該機制發生的時間是由GC線程決定的,若是不發生GC就永遠不會發生這個機制,最後,若是這個機制使用不當,就會嚴重影響GC性能。

對象的三種狀態

  • 可觸及狀態

    • 正常使用的對象
  • 可復活狀態

    • 對象不可觸及,可是在finalization中被複活
  • 不可觸及狀態

    • 對象不能被複活,真正要被回收以前的狀態。

虛擬機在斷定一個對象是否被回收的時候,須要進行兩次標記,第一次,判斷該對象從根對象集合開始有沒有引用鏈,,而後判斷對象是否須要執行finalization()方法,若是該對象沒有重寫finalization()方法,活着以前已經調用過該方法(這個方法只能被調用一次),那麼就認爲不須要執行,那麼該對象也就達到了第三種狀態。

若是該對象重寫了finalization()方法,且未執行過,那麼該對象就會被插入一個隊列中,由虛擬機自動建立一個低優先級的finalizer線程觸發其finalization()方法,進行第二次標記,若是方法中,對象忽然復活,就會將其移除即將回收的集合,達到第二個復活狀態。

垃圾清除

標記清除算法

將全部具備引用執行的對象進行標記,對未標記的的對象進行清除。

因爲清除階段須要對全部對象進行遍歷,因此效率不高,並且清除的空間是碎片化的,須要維護一個空閒列表。

複製清除算法

對全部存活的對象不進行標記,而是直接將其複製到另一塊如出一轍大小的空間中去,而後對原來空間進行總體回收。這樣作的好處是沒有標記和清除過程,使得清除十分高效,複製過去的內存空間是連續的,不須要維護空閒表。可是須要兩倍的內存空間,並且對象的複製會到值棧中引用地址會發生變化。

標記壓縮算法

複製算法創建在存活對象少,垃圾比較多的狀況下。該算法就是在標記清除算法的基礎上進行了碎片整理,這樣就不須要維護空閒列表。可是效率比標記清除算法更低。

分代收集算法

按照不一樣的分區選擇不一樣的算法。在新生區,因爲對象具備朝生夕死,回收頻率高的特性,因此能夠採用回收效率較高的複製算法。而對於老年區,因爲對象的生命週期較長,並且空間比較大,回收頻率不高,咱們就能夠採用標記清除,標記壓縮算法或者混合使用。

增量收集算法

還是傳統的標記-清除算法和複製算法,只是經過經過分階段的方式處理線程衝突問題,容許垃圾回收線程分階段完成清理和複製。可是頻繁的進行線程切換會形成垃圾回收的總成本升高,系統的吞吐量降低。

分區算法

將堆空間劃分爲不少個小空間,根據目標的停頓時間,每次合理的回收若干個小區間,從而減小一次GC所產生的停頓。

內存泄露

當一個對象不被使用的時候,jvm會自動對其進行回收,可是若是出現一些意外狀況致使垃圾回收器沒有對其回收,這樣的現象,咱們就叫他內存泄露,簡單來講,就是對象不能被使用了,可是還不能回收掉,長期佔用必定的內存空間。那麼在哪些狀況下會產生內存泄露?

當存在一些複雜的指針指向,若是存在對象不使用了,因而不少指針都放開,可是某一個指針沒有放開,致使這些對象中。仍然有部分指針沒有斷開,而形成對象不能被回收。

另外,在單例模式中,單例的生命週期和應用程序的週期是同樣長的,因此單例程序中,若是持有對不對象的引用的狀況,那麼這個外部對象就不能被回收,就會致使內存泄露。

還有一些就是資源未關閉鏈接的行爲,數據庫鏈接,網絡鏈接,io操做等,就會致使對象不會被回收(主要是一些和外部資源有鏈接的對象)。

引用

強引用

相似new出來的對象,只要引用還在就永遠不會進行回收。

Object o = new Object();

軟引用

若是出現內存不足就會對軟引用對象進行回收。

SoftReferencre<User> usersoftRef = new SoftReference<User>(new User("zero",18));

弱引用

生命週期僅存在於下一次垃圾回收以前,也就是隻要發生GC就必定會回收弱引用。

WeakReference<User> userweakreference = new WeakReference<User>(new User("zero",18));

虛引用(對象回收跟蹤)

虛引用顧名思義,就是形同虛設。與其餘幾種引用都不一樣,虛引用不會決定對象的生命週期。若是一個對象僅持有虛引用,那麼它就和沒有任何引用同樣,在任什麼時候候均可能被垃圾回收器回收。

垃圾回收器

serial回收器(串行回收)

應用場景是在單核CPU的狀況下使用一條收集線程去完成清理工做,在垃圾回收期間,其餘全部的工做線程都要停下來,直到垃圾回收線程完畢。在其特殊的工做場景下,他的回收效率是最高的,由於他不須要反覆進行多線程的切換。一般和Serial Old GC搭配工做。

ParNew回收器(並行回收)

採用並行回收的方式,其餘跟serial回收器十分相似。主要運用在多CPU的環境下。能夠和CMS GC以及 Serial Old GC搭配工做。

Parallel Scavenge回收器(吞吐量優先)

一個採用了複製算法,並行回收和stw機制的垃圾回收器。由此可知,該回收器的目標是注重吞吐量,

他和採用了標記-壓縮算法、並行回收、stw機制的Parallel Old 收集器搭配, 效果很是好。(是jdk8的默認垃圾回收器)

cms回收器(併發收集器)

第一款能讓垃圾回收線程和用戶線程同時進行工做的回收器。他的關注點是儘量縮短垃圾回收時用戶線程的停頓時間,提升響應速度。

採用標記-清除算法,因此在垃圾回收以後會產生一些碎片空間,只能引用空閒列表的方式來執行後續的內存分配。

對CPU的資源也很敏感,在併發階段由於會佔用一部分線程,從而使程序變慢,總吞吐量也會下降。

沒法處理浮動垃圾。在第二階段的併發標記過程完成後,由於用戶線程的某些操做使得某些以前不是垃圾的對象變成了垃圾,可是第三階段的重寫標記只是進行對以前懷疑是垃圾的對象確認一下是不是真的垃圾,不會標記新產生的這部分浮動垃圾。也就不會回收這部分垃圾。

流程:

  • 初始標記

    • 全部的工做線程都會出現短暫的stw,這個階段的工做目的是標記全部GC Root能直接關聯的對象,一旦標記完成就會恢復全部暫停線程,因爲關聯的對象比較小,因此速度很是快
  • 併發標記

    • 從GC root直接關聯的對象開始遍歷整個關聯對象圖的過程,這個過程耗時較長,可是不須要暫停用戶線程,能夠與垃圾收集併發運行。
  • 從新標記

    • 修正標記期間,由於用戶進程繼續運行致使標記變更的那部分對象的標記記錄,這個階段的停頓時間會比初始階段長,但遠比並發標記階段時間短。
  • 併發清除

    • 清理刪除標記階段判斷的已經不使用的對象,釋放內存空間。這個階段不須要移動存活的對象,因此也是能夠和用戶線程併發執行的。

G1垃圾回收器(區域分代化)

一個並行回收器,將堆內存劃分紅多個不想關的區域(物理上不連續),不一樣的區域表示不一樣的堆分區(Eden,s0,s1,old),這樣作的目的是避免在堆中作全區域的回收,經過跟蹤每一個區域的回收價值(回收得到的空間大小以及所需時間比例)維護一個優先級列表,根據容許回收的時間,選擇回收價值大的區域進行回收。

特色:

  • 並行性

    • 在回收期間可有多個GC線程同時工做,利用多核的特性,減小用戶線程的stw。
  • 併發性

    • G1擁有於用戶線程交替執行的能力,因此整個回收階段發生不會徹底阻塞程序的執行。
  • 分代收集

    • 將整個堆空間分爲若干個區域,每一個區域都表明堆空間的原始分區的一部分,並且他的回收不像其餘回收器同樣,他是兼顧新生區和老年區的,
  • 空間整合

    • 區域之間採用的是複製算法,而總體是標記壓縮算法。在進行垃圾回收以後,不會有碎片化的空間,避免了後續空間分配帶來的許多問題。
  • 可預測的停頓時間模型

    • G1除了追求低停頓以外,還創建可預測的停頓時間模型,讓使用者在M的時間片斷內,讓垃圾回收的時間不超過n。

回收環節:

  • 年輕代GC

    • 當Eden內存空間不足的時候,就會進行YGC,這個時候他是一個並行的獨佔式的收集器,全部的用戶線程都會停下來,將Eden中的存活對象放到s區,大對象直接放到老年區。
  • 老年代併發標記

    • 和cms 的清理過程相似
  • 混合回收

    • 會同時回收新生區和老年區的垃圾。
相關文章
相關標籤/搜索