標籤(空格分隔): Java算法
JVM內存結構主要包括: 方法區, 堆區, 程序計數器, 本地方法區, 虛擬機棧. 其中的程序計數器, 本地方法區, 虛擬機棧這三個區域是的生命週期隨線程生滅, 因此不須要過多考慮這方面的GC問題.數據結構
在JDK1.2以後, Java對引用的概念進行了補充, 整體分爲四類: 強引用, 軟引用, 弱引用, 虛引用. 這四種引用強度逐漸減弱.多線程
Object object = new Object();
這類的引用, 只有強引用還存在, GC就永遠不會收集被引用的對象.OutofMemoryError
以前), 纔會被垃圾回收. 採用SoftReference
類來實現軟引用.WeakReference
類來實現弱引用.PhantomRenference
類實現.爲每個對象的的數據結構添加一個引用計數器, 用於統計指向該對象的引用的數量, 每當多一個引用的時候, 其引用計數器就加一, 當引用再也不指向該地址以後計數器減一. 一旦計數器的值爲0,則表示沒有引用指向該對象, 則對象已經死亡 (
<<
尋夢環遊記>>
說的: 人真正的死亡是全部活着的人的都忘了你的時候).佈局
優勢:線程
缺點:3d
目前JVM的主流垃圾回收器採起的可達性分析算法, 這個算法的實質在於將一系列
GC Roots
做爲初始的存活對象的集合(Live Set
), 而後從該集合出發, 探索全部能過被集合直接或間接引用的對象, 而且將其加入集合之中, 這個過程就是標記過程. 最終, 未被探索到的對象即是死亡, 是能夠回收的.代理
什麼是GC Roots
, 其實就是由堆外指向堆內的引用.code
可達性分析, 能夠解決循環引用問題, 可是自身也存在一些問題, 好比說在多線程的狀況下, 其餘線程可能會更新已經訪問過的對象的引用, 形成漏刪. 解決方案是 進行兩次可達性分析, 若是兩次某對象都被標記則進行刪除.對象
由名可得: 標記
->
清除. 獲得須要清除的對象以後就直接進行清除.blog
優勢: 速度快
缺點: 屢次GC以後, 形成大量的碎片空間. 對於須要連續存儲的較大對象沒法存儲, OutofMemoryError
由名可得: 標記
->
清除->
移動整理. 對標記清除算法
的一次改進, 可是由於移動操做, 因此時間成本較高.
優勢: 沒有內存碎片.
缺點: 時間成本較高.
將可用的內存按容量分爲大小兩塊, 每次只是用其中一塊, 當這一塊的內存用完了, 就將還存活着的對象複製到另外一塊內存上, 而後再把已使用的內存空間清理掉.
每次當內存分配的時候空間不夠的時候, 都進行復制算法進行內存整理.
優勢: 實現簡單, 效率高. 解決了標記清除算法致使的內存碎片問題.
缺點: 代價太大, 將內存縮小了一半. 效率隨對象的存活率升高而下降.
Eden
和兩塊較小的Survivor
空間.Eden
和其中Survivor
空間.Eden
和Survivor
空間中存活的對象一次性的複製到另外一塊Survivor
空間上.Eden
和使用過的Survivor
空間.Hotspot
默認Eden
和Survivor
的大小比例是8:1 .
分配擔保:
若是另外一塊Survivor
空間沒有足夠的內存來存放上一次新生代收集下來的存活對象, 那麼這些對象則直接經過擔保機制進入老年代.
當前商業虛擬機的垃圾收集器都是採用分代收集算法, 根據對象存活週期的不一樣將內存劃分爲幾塊. 通常把
Java
堆分爲新生代, 老年代. JVM根據各個年代的特色採用不一樣的手機算法.
Java堆是JVM所管理的內存的最大的一塊, 也是GC主要的工做區. 其主要分爲兩個區
年輕代
和老年代
, 其中年輕代又分爲Eden
和Survivor
區, 其中Survivor
區又分爲FROM
和To
兩個區. 可能這個時候你們又會有疑問, 爲何須要Survivor
區, 爲何Survivor
還要分爲兩個區?
Eden
區 : IBM表示有98%的對象是朝生夕死, 因此針對這一現狀, 大多數狀況下, 對象會在新生代Eden
區中進行分配, 當Eden
區沒有足夠的空間進行分配的時候, 虛擬機會發起一次GC
. 經過此次GC
以後,Eden
會被清空,Eden
區中絕大部分的對象會被回收, 而那些無需回收的存貨對象, 將會進到Survivor
的FROM
區(若FROM
不夠, 則直接進入Old
區).
Survivor
區: 至關因而Eden
區和Old
區的一個緩衝, 相似於咱們交通中的黃燈.Survivor
又分爲兩個區, 一個爲From
區, 一個是To
區. 每次執行Minor GC
會將Eden
區和FROM
存活的對象放到Survivor
的To
區(若是To
則直接進入Old
區).
不是新生代到老年代麼, 直接中
Eden
到Old
很差了麼,爲何要這麼複雜. 若是沒有Survivor
區,Eden
區每一次GC
, 存活的對象就會被送到老年代, 老年代很快就會被填滿, 而雖然有不少對象雖然一次沒有被消滅掉,可是也存活不了太屢次, 這個時候將其移入Old
區會很快的將其填滿.
因此
Survivor
的存在乎義就是減小被送到老年代的對象, 進而減小GC
的發生.Survivor
的篩選保證, 只有經歷16此的GC還能再新生代存活的對象,纔會被送到老年代.
Old區佔據着
2/3
的堆內存空間,只有在Marjor GC
的時候纔會進行清理, 每次GC
都會出發stop-the-world
. 內存越大,SWT
的時間也越長, 因此內存也不只僅是越大越好, 因爲複製算法的對象存活率較高的老年代會進行不少次的複製操做, 效率很低, 因此老年代這裏採用的是 標記整理算法.
除了上述所說, 在內存擔保機制的狀況下, 沒法安置的對象也會直接進入老年代, 如下幾種狀況也會進入老年代.
Eden
區以及兩個Survivor
區之間發生大量的內存複製, 當你的系統有很是多的"朝生夕死"的大對象的時候, 就值得注意了.Survivor
的FROM
和To
之間進行移動, 對象在每經歷一次Minor GC
, 年齡就會自增1, 當年齡增長到15歲的時候, 就會被移入老年代. 這裏的15是能夠進行自定義的.Survivor
空間中相同年齡全部對象的總和大於Survivor
空間的通常, 年齡大於等於該年齡的對象就能夠直接進入老年區.