摘要:語言使用了內(nèi)存動態(tài)分配和垃圾回收技術(shù),掌握這些不僅可以提高自己的逼格,而且為后續(xù)的調(diào)優(yōu)打下扎實的基礎(chǔ),讓自己離架構(gòu)師更近一步。任何引用計數(shù)器為的對象實例可以被當作垃圾收集。引用計數(shù)是垃圾收集器中的早期策略。
JVM之垃圾回收
市面上有關(guān)JVM垃圾回收的文章很多,有些是針對垃圾收集器,有些是介紹垃圾回收算法,也有些各方面都有涉及。本文希望能做一個比較全面的總結(jié),最關(guān)鍵的是形成自己的語言,有自己的理解和沉淀。
一、為什么需要垃圾回收大家都知道,java語言的內(nèi)存是動態(tài)分配的,不像C++語言還需要開發(fā)者專門干預,在一定程度上可以提高開發(fā)效率。那么大家可能疑問:既然不需要我們開發(fā)者關(guān)心,我們?yōu)槭裁催€要討論?作為一個程序語言的駕馭者,必然需要掌握該語言的方方面面,包括底層的原理和機制。
Java語言使用了內(nèi)存動態(tài)分配和垃圾回收技術(shù),掌握這些不僅可以提高自己的逼格,而且為后續(xù)的JVM調(diào)優(yōu)打下扎實的基礎(chǔ),讓自己離架構(gòu)師更近一步。
JVM的內(nèi)存結(jié)構(gòu)包括五大區(qū)域:程序計數(shù)器、虛擬機棧、本地方法棧、堆區(qū)、方法區(qū)。其中程序計數(shù)器、虛擬機棧、本地方法棧3個區(qū)域隨線程而生、隨線程而滅,因此這幾個區(qū)域的內(nèi)存分配和回收都具備確定性,就不需要過多考慮回收的問題,因為方法結(jié)束或者線程結(jié)束時,內(nèi)存自然就跟隨著回收了。而Java堆區(qū)和方法區(qū)則不一樣,這部分內(nèi)存的分配和回收是動態(tài)的,正是垃圾收集器所需關(guān)注的部分。
垃圾收集器在對堆區(qū)和方法區(qū)進行回收前,首先要確定這些區(qū)域的對象哪些可以被回收,哪些暫時還不能回收,這就要用到判斷對象是否存活的算法。
1、引用計數(shù)法
在這種方法中,堆中每個對象實例都有一個引用計數(shù)。任何引用計數(shù)器為0的對象實例可以被當作垃圾收集。
引用計數(shù)是垃圾收集器中的早期策略。該方法看似很實用,但是解決不了循環(huán)引用的問題(比如循環(huán)鏈表)。
2、可達性分析算法
從一個節(jié)點GC ROOT開始,尋找對應的引用節(jié)點,然后尋該引用節(jié)點的引用節(jié)點,當所有的引用節(jié)點尋找完畢之后,剩余沒有被引用的節(jié)點將會被判定為是可回收的對象。
3、引用分類
在Java語言中,將引用又分為強引用、軟引用、弱引用、虛引用四種,這四種引用強度依次逐漸減弱。垃圾回收算法都是基于強引用而言的。
三、垃圾回收算法1、標記-清除算法
標記-清除算法從根集合(GC Roots)開始掃描,對需要繼續(xù)存活的對象進行標記,標記完畢后,再掃描整個空間中未被標記的對象,進行回收,如下圖所示。
標記-清除算法只需對不需要存活的對象進行處理,在存活對象比較多的情況下極為高效,但是會造成內(nèi)存碎片。
2、復制算法
復制算法的提出就是為了解決內(nèi)存碎片的問題,如下圖所示。復制算法雖然解決了內(nèi)存碎片的問題,但是浪費一半內(nèi)存。另外在對象存活率很高的時候,復制成本會非常高。
3、標記-整理算法
標記-整理算法是在標記-清除算法的基礎(chǔ)上,又進行了對象的移動,因此成本更高,但是卻解決了內(nèi)存碎片的問題。具體流程見下圖:
4、分代收集算法
一般情況下將堆區(qū)劃分為老年代(Tenured Generation)和新生代(Young Generation),老年代的特點是每次垃圾收集時只有少量對象需要被回收,而新生代的特點是每次垃圾回收時都有大量的對象需要被回收,那么就可以根據(jù)不同代的特點采取最適合的收集算法。
新生代采用復制算法;老年代采用標記-整理算法。
其中年輕代內(nèi)存分配過程如下:
1) 絕大多數(shù)剛創(chuàng)建的對象會被分配在Eden區(qū),其中的大多數(shù)對象很快就會消亡;
2) 最初一次,當Eden區(qū)滿的時候,執(zhí)行Minor GC,將消亡的對象清理掉,并將剩余的對象復制到一個存活區(qū)Survivor0;
3) 下次Eden區(qū)滿了,再執(zhí)行一次Minor GC,將消亡的對象清理掉,將存活的對象復制到Survivor1中,然后清空Eden區(qū);
4) 將Survivor0中消亡的對象清理掉,將其中可以晉級的對象晉級到Old區(qū),將存活的對象也復制到Survivor1區(qū),然后清空Survivor0區(qū);
5) 然后跳到第三步,當兩個存活區(qū)切換了幾次(HotSpot虛擬機默認15次,用-XX:MaxTenuringThreshold控制)之后,仍然存活的對象,將被復制到老年代。
1、新生代收集器
1) Serial收集器
單線程收集器
2) ParaNew收集器
Serial收集器的多線程版,關(guān)注縮短垃圾收集時間。(使用-XX:+UseParNewGC開關(guān)來控制使用ParNew+Serial Old收集器組合收集內(nèi)存;使用-XX:ParallelGCThreads來設(shè)置執(zhí)行內(nèi)存回收的線程數(shù)。)
3) Parallel Scavenge收集器
關(guān)注CPU吞吐量,即運行用戶代碼的時間/總時間。(使用-XX:+UseParallelGC開關(guān)控制使用Parallel Scavenge+Serial Old收集器組合回收垃圾(這也是在Server模式下的默認值);使用-XX:GCTimeRatio來設(shè)置用戶執(zhí)行時間占總時間的比例,默認99,即1%的時間用來進行垃圾回收;使用-XX:MaxGCPauseMillis設(shè)置GC的最大停頓時間;使用-XX:+UseAdaptiveSizePolicy可以進行動態(tài)控制Eden/Survivor比例,老年代對象年齡,新生代大小等。)
2、老年代收集器
1) Serial Old收集器
單線程收集器
2) Parallel Old收集器
Parallel Scavenge收集器的老年代版本(使用-XX:+UseParallelOldGC開關(guān)控制使用Parallel Scavenge +Parallel Old組合收集器進行收集。)
3) CMS收集器
多線程,優(yōu)點是并發(fā)收集(用戶線程可以和GC線程同時工作)
3、G1收集器
特性:
1) 首先收集盡可能多的垃圾(Garbage First)
內(nèi)部采用了啟發(fā)式算法,找出具有高收集收益的分區(qū)進行收集。
2) 并行和并發(fā)
和CMS相似,可以做到用戶線程和GC線程同時工作。
3) 內(nèi)存布局調(diào)整
將整個堆劃分為多個大小相等的獨立區(qū)域(Region),新生代和老年代不再是物理隔離,它們都是一部分Region(不需要連續(xù))的集合。每個分區(qū)都可能隨G1的運行在不同代之間前后切換。
G1劃分了一個Humongous區(qū),它用來專門存放巨型對象。
4) GC模式
G1提供了兩種GC模式,Young GC和Mixed GC,兩種都是Stop The World(STW)的。
[1] https://blog.csdn.net/ft30597...
[2] https://www.cnblogs.com/1024C...
[3] https://blog.csdn.net/x_i_y_u...
[4] https://www.jianshu.com/p/e99...
[5] https://blog.csdn.net/foolish...
[6] https://blog.csdn.net/coderli...
[7] https://www.cnblogs.com/ASPNE...
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/72586.html
摘要:垃圾回收算法與垃圾回收器綜述我們常說的垃圾回收算法可以分為兩部分對象的查找算法與真正的回收方法。串行垃圾回收器一次只使用一個線程進行垃圾回收并行垃圾回收器一次將開啟多個線程同時進行垃圾回收。 垃圾回收算法與 JVM 垃圾回收器綜述歸納于筆者的 JVM 內(nèi)部原理與性能調(diào)優(yōu)系列文章,文中涉及的引用資料參考 Java 學習與實踐資料索引、JVM 資料索引。 showImg(https://s...
摘要:年輕代的目標就是盡可能快速的收集掉那些生命周期短的對象。年老代在年輕代中經(jīng)歷了次垃圾回收后仍然存活的對象,就會被放到年老代中。什么情況下觸發(fā)垃圾回收由于對象進行了分代處理,因此垃圾回收區(qū)域時間也不一樣。 [TOC] 與C/C++相比,java語言不需要程序員直接控制內(nèi)存回收,java程序的內(nèi)存分配和回收都是由JRE在后臺自動進行,JRE會負責回收那些不再使用的內(nèi)存,這種機制被稱為垃圾...
摘要:直接對棧的操作只有兩個,就是對棧幀的壓棧和出棧。中將永久代移除,同時增加元數(shù)據(jù)區(qū)。在中,本地方法棧和虛擬機棧是在同一塊兒區(qū)域,這完全取決于技術(shù)實現(xiàn)的決定,并未在規(guī)范中強制。 原文:https://github.com/linsheng97... 描述一下 JVM 的內(nèi)存區(qū)域 程序計數(shù)?(PC,Program Counter Register)。在 JVM 規(guī)范中,每個線程都有它自己的...
摘要:概要要理解的內(nèi)存管理策略,首先就要熟悉的運行時數(shù)據(jù)區(qū),如上圖所示,在執(zhí)行程序的時候,虛擬機會把它所管理的內(nèi)存劃分為多個不同的數(shù)據(jù)區(qū),稱為運行時數(shù)據(jù)區(qū)。 這是一篇有關(guān)JVM內(nèi)存管理的文章。這里將會簡單的分析一下Java如何使用從物理內(nèi)存上申請下來的內(nèi)存,以及如何來劃分它們,后面還會介紹JVM的核心技術(shù):如何分配和回收內(nèi)存。 JMM ( Java Memory Model )概要 show...
閱讀 2330·2021-11-25 09:43
閱讀 3467·2021-10-25 09:48
閱讀 1340·2021-09-13 10:24
閱讀 2753·2019-08-29 15:07
閱讀 1288·2019-08-29 13:14
閱讀 3281·2019-08-29 12:22
閱讀 1365·2019-08-29 11:32
閱讀 3255·2019-08-29 11:23