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