Java 垃圾回收

垃圾回收算法:

第一步,確認垃圾的步驟

1.引用計數法

就是在程序運行過程中,當一個變量被引用的時候,對這個變量進行計數,被引用一次的時候,這個時候這個變量的計數器就加一,當這個對象的引用被釋放了不進行引用了,此時計數器就減一,當計數器爲0的時候,此時進行垃圾回收,回收這個變量

這種垃圾回收算法,

優點:

實現簡單,使用的過程比較方便,當進行垃圾回收只需要關注計數器的情況,不需要進行全局進行掃描 ,回收效率高。

缺點:

需要維護計數器,每一次的變量引用都要去相應修改對應的計數器,導致性能的下降。

加大對內存的消耗,去維護計數器

最大的問題就是無法解決循環引用的問題

2.根搜索算法(這個我自己方便記)。(可達性分析算法)

這種算法是,實在解決循環引用的情況,就是 我們開啓全局搜索的形式,採用樹的形式,進行搜索,進行遍歷,從根節點進行出發,找到從根節點無法到達的節點,進行回收,

優點:

解決了循環引用的問題,實現了垃圾回收算法的可用性,

缺點:

需要進行全局掃描,影響程序的性能

第二步:進行垃圾的回收

1.標記-清除算法

標記清除算法:是最基礎的一種垃圾回收算法,

對可以回收的對象進行標記,然後把對應標記的對象進行回收,這種算法的最大的問題就是,內存的碎片。進行垃圾回收後,導致內存的存儲並不是連續的。假如 剩餘的內存的大小爲1M,但是此時因爲內存不是連續的,我用一個Arraylist 申請一塊1M內存,本身是可以支持,但是因爲內存存在碎片,導致並不能成功,導致內存的溢出。

2.標記-清除-壓縮算法(不是亞索哦。)---》(標記-整理算法)(老年代使用的算法)

標記過程仍與標記-清除過程一致,但是進行標記後,不是直接進行垃圾的回收,而是把所有的存活的對象,向一端進行移動,清理掉界限外的垃圾對象,有效解決了內存碎片的問題。

3.複製算法(重要算法  新生代使用的算法)

複製算法,是把對應的內存分爲相同的兩個,每次都只使用其中的一塊內存,當一塊用完的時候,就將這塊中還在存活的對象,進行復制,複製到另外一塊內存中去,並且交換兩塊內存的名字 from-》to ,to->from 這樣也會解決內存碎片化的問題,但是 弊端就是,內存本來又500M 實際使用的大小,僅爲250M 大大降低了內存的使用效率。

二者比較來說,標記整理算法對內存變動更頻繁,需要整理所有存活對象的引用地址,在效率上比複製算法要差很多。

4.分代算法(JVM使用的算法)

分代算法,說白並不是一種新的算法, 只不過把java 把內存模型,分爲不同的代。新生代。老年代,永久代,

當對象剛剛被new之後,優先在新生代進行存儲,因爲新生代的對象,都是新生成的對象,可能每次用過之後就被廢棄了。

導致大量的對象死亡,所以在新生代的中,採用的垃圾回收算法應該是高效的,並且不應該是又碎片化。

所以在 新生代的算法應爲 複製算法。在新生代的內存模型中,分爲 Eden區和Survivor(分爲 From區和 TO區)

大多數情況下,對象會在新生代Eden區中分配。當Eden區沒有足夠空間進行分配時,虛擬機會發起一次 Minor GC。Minor GC相比Full GC更頻繁,回收速度也更快。通過Minor GC之後,Eden區中絕大部分對象會被回收,而那些存活對象,將會送到Survivor的From區(若From區空間不夠,則直接進入Old區) 。

Survivor區相當於是 新生代和老年代之間的緩衝區。

因爲假如不存在Survicor區的話。假如當新生代滿了之後進行Minor GC 此時,存活對象被送往老年區。老年區很快就會被擠滿。會導致更快進行Full GC 而Full GC 的時候會對老年區進行垃圾回收,而老年區採用的是 標記整理算法,大大低於複製算法的效率,此時大大影響程序的性能,因爲 一般新生的對象可能第一次Minor GC 沒有被回收掉。但是可能第二次 第三次就會被回收掉,這樣可以大大的提高程序的性能。只有經歷16次Minor GC還能在新生代中存活的對象,纔會被送到老年代

而在Survicor區中,主要分爲兩個區域 From 區和To區。兩者採用複製算法一直進行着交換角色,進行垃圾的回收

大對象直接進入老年代:因爲大對象進入到新生代的話 ,會導致的問題就是,因爲在新生代中採用的複製算法,內存很快被沾滿,但是複製算法對大對象,複製很是消耗程序的效率

面試題: 請問了解Minor GC和Full GC麼,這兩種GC有什麼不一樣嗎?

Minor GC又稱爲新生代GC : 指的是發生在新生代的垃圾收集。因爲Java對象大多都具備朝生夕滅的特性,因此Minor GC(採用複製算法)非常頻繁,一般回收速度也比較快。
Full GC 又稱爲老年代GC或者Major GC : 指發生在老年代的垃圾收集。出現了Major GC,經常會伴隨至少一次的Minor GC(並非絕對,在Parallel Scavenge收集器中就有直接進行Full GC的策略選擇過程)。Major GC的速度一般會比Minor GC慢10倍以上。

一般是把Java堆分爲新生代和老年代。在新生代中,每次垃圾回收都有大批對象死去,只有少量存活,因此我們採用複製算法;而老年代中對象存活率高、沒有額外空間對它進行分配擔保,就必須採用"標記-清理"或者"標記-整理"算法。

三:垃圾回收器

1.串行垃圾回收

JDK1.5前的默認算法

就是垃圾回收算法和當前運行線程,使用同一個線程進行垃圾回收。導致的問題是,當進行垃圾回收的時候,運行的程序需要暫停。(STW)在web開發的時候(響應速度),是無法忍受的。

使用單線程處理所有垃圾回收工作,因爲無需多線程交互,所以效率比較高。但是,也無法使用多處理器的優勢,所以此收集器適合單處理器機器

2.並行垃圾回收

就是垃圾回收和當前的線程並不是同一個線程。而是開闢另一個線程進行垃圾的回收。多個線程執行垃圾回收

適合於吞吐量的系統,回收時系統會停止運行

3.CMS垃圾回收(併發)

在程序運行的同時進行垃圾的回收

首先說明的是:

CMS並非沒有暫停,而是用兩次短暫停來替代串行標記整理算法的長暫停,它的收集週期是這樣:

CMS回收的方式:主要分爲一下幾個階段:初始標記(暫定)
併發標記(Concurrent marking)
併發預清理(Concurrent precleaning)
重新標記(暫停)
併發清理(Concurrent sweeping)
併發重置(Concurrent reset)

別人的圖

https://blog.csdn.net/u012794505/article/details/79594956

總得來說,CMS回收器減少了回收的停頓時間,但是降低了堆空間的利用率。

CMS使用場景
如果你的應用程序對停頓比較敏感,並且在應用程序運行的時候可以提供更大的內存和更多的CPU(也就是硬件牛逼),那麼使用CMS來收集會給你帶來好處。還有,如果在JVM中,有相對較多存活時間較長的對象(老年代比較大)會更適合使用CMS。

4.G1垃圾回收

在 jdk1.7 之後引入的新的垃圾回收的方式,。

  1. 年輕代、老年代是獨立且連續的內存塊;
  2. 年輕代收集使用單eden、雙survivor進行復制算法;
  3. 老年代收集必須掃描整個老年代區域;
  4. 都是以儘可能少而塊地執行GC爲設計原則

 

 

G1垃圾回收:https://blog.csdn.net/coderlius/article/details/79272773

 

引用:https://blog.csdn.net/yubujian_l/article/details/80804708

https://www.jianshu.com/p/23f8249886c6

發佈了37 篇原創文章 · 獲贊 9 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章