【java】垃圾回收機制與算法

之前看了一些java的垃圾回收機制的文章,感覺全網都有,但是寫的參差不齊,有的寫的超好,有的總覺得怪怪的,所以還是自己整理一番!(如有雷同,純屬抄襲。。。)

哎,“寒冬”啊,大家日子都不好過!

概念:

垃圾回收機制就是當你寫你的java代碼的時候,基本不需要考慮內存資源的佔用和釋放,爲什麼說基本不需要考慮呢,因爲java有垃圾回收機制來幫你做這件事情,但是爲什麼又沒有說完全不考慮呢?因爲如果你的代碼寫的稀爛,OOM是很常見的操作!所以垃圾回收機制,就是幫你清理掉已經沒有用的內存佔用(比如一些用完不會再用的對象),但是我們需要減少GC

 

垃圾回收算法:

那市面上都有哪些常見的垃圾回收算法呢?

1、標記-清除法(Mark-Sweep)

很好理解,兩個步驟,先找到存活的對象(標記),接着當執行垃圾回收的時候,清除其他對象。是最原始最基礎最簡單的算法

缺點:對象被刪除之後,沒有整理過堆(heap),結果產生大量不連續的內存碎片,當我們創建一個大對象(大對象需要連續的一整塊內存,比如一個很長的集合,Map等),就會導致提前觸發下一次的GC

這張圖來自:https://www.cnblogs.com/jiangtunan/p/11025521.html(作者:將圖南)

 

2、複製算法(Copying)

怕內存被碎片化,所以提出新的解決方案。

直接把內存砍成兩半(叫A和B),在使用A的時候,B是空的,當觸發垃圾回收的時候,把A中存活的對象複製到B中,然後清空A,接着新來的對象,就放入B中,以此類推循環往復。

缺點:太明顯了好嗎,我買了16G的內存,結果最大隻能用8G????還有另外一個缺陷,對象存活率比較高,那麼就會出現一大部分數據反覆的複製過來複制過去

這張圖來自:https://blog.csdn.net/yrwan95/article/details/82829186(作者:蜜汁蛋總)

 

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

有一些垃圾回收器,使用了標記-清除法(Mark-Sweep)之外,還會週期性的調用標記-整理算法,用來對堆的碎片進行定期的整理!

先找到存活的對象(標記)

然後將存活的對象按照一定的規則挪到同一側(或者同一邊),

更新存活對象的應用的指針值(因爲實際堆中的對象換了位置,所以棧中對象的引用指針需要更新)

然後清空邊界以外的所有對象

這其中還涉及到按照什麼規則排?

(具體我就不展開了,大家有興趣可以看如下pdf,應該是需要翻牆的)

http://www.cs.tau.ac.il/~maon/teaching/2014-2015/seminar/seminar1415a-lec2-mark-sweep-mark-compact.pdf

缺點:這種算法其實還蠻不錯的了

缺點就是需要更多的空間來存儲引用(不過java本身new對象的時候就是引用+堆中的對象)

通常比標記-清除複製算法更慢,需要更多的堆的傳遞(因爲把堆上的對象做了一定規則的排序)

pdf中的原文:

Has some space overheads incurred bystoring forwarding addresses.

 Usually has a slower throughput than marksweep or copying GC, as it requires more passes over the heap.

這張圖來自:https://blog.csdn.net/wuzhiwei549/article/details/80563134(作者:1Vincent)
 

4、分代收集算法(Generational Collection)

分代要滿足一個假設:絕大多數的對象生命週期都非常短暫,甚至有些用一次之後就不用了!

核心:把內存分爲兩部分,兩部分使用不同的垃圾收集機制

比如分爲新生代和老年代,新生代每次都有大比例的對象死去,那就可以用複製算法,老年代,對象存活率高,就可以用標記整理,java就是這麼做的!

 

java中垃圾回收簡述:

java垃圾回收就是分代收集算法的一種延伸,每個內存空間又有自己獨有的處理方式

1、對象先創建到Eden中

2、當新對象創建的時候,Eden區已經放不下了,就會發生一次Minor GC,這是小規模的GC手段,目的就是清理Eden空間,將Eden中存活的對象挪到Survivor的From中,等到下一次Minor GC時候,會將Eden中存活的+SurvivorFrom中存活的全部挪到To中,下一次再反過來挪到From中,存活的對象每挪動一次,年齡就會+1。以此類推

啥時候年輕代的對象會進入老年代呢?

內存分配與回收策略(對象晉升老年代):https://www.jianshu.com/p/0772dc04e1d9(作者:是一動不動的friend)

3、當有對象進入到老年代,如果老年代滿了就會清理老年代,這是一個非常耗時的GC(我們需要儘量避免觸發這類的GC)

爲什麼我這裏沒有寫Full GC呢,因爲具體我也不確定到底觸發的是哪種,我估計是Full GC,大家如果想深入研究可以看如下的鏈接

  • Major GC 是清理老年代。
  • Full GC 是清理整個堆空間—包括年輕代和老年代。

Minor GC、Major GC和Full GC之間的區別:https://www.cnblogs.com/tuhooo/p/7508503.html(作者也是轉載的)

如下圖是java的heap中內存分配的比例 :

 

java官網相關參數的設置和默認值:https://www.oracle.com/java/technologies/vmoptions-jsp.html

JVM內存配置詳解:https://www.cnblogs.com/qmfsun/p/5396710.html(作者:Agoly)

 

我們是可以通過不同的參數來設置這些值的比例的,具體還是要根據自己項目來判定

每個個接口每秒會接受多少請求,每個請求會創建多大的對象,每秒會有多少對象進入到Eden,這些對象是否是臨時對象等等一系列問題
 

最後的最後,說一個問題,看到很多文章說垃圾回收算法是找到要需要刪除的對象,然後刪除那些對象,我想這樣說是錯誤的,應該是找到存活的對象,那麼通過什麼手段尋找呢?

叫做可達性分析算法(GC Roots,大概來說就是從一些可以作爲“根”(root)的節點往下尋找存活的對象,並且標記這些(存活)對象(具體也不是我三言兩語就能說明白的)。

大家有興趣可以去研究下

JAVA垃圾回收-可達性分析算法:https://blog.csdn.net/luzhensmart/article/details/81431212(翻譯作者:這瓜保熟麼)

 

菜雞一隻,正在努力提升自己,本文如果有哪些寫的不對的,歡迎大家指出,我一定及時更改!

(接下來想看看java不同垃圾回收的區別,比如什麼G1,什麼CMS),下次再見拜拜~

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