淺談Java的內存分配和垃圾回收

此文爲本人閱讀了《深刻理解Java虛擬機》的內存管理部分知識所整理的較簡要的讀書筆記。算法

自動內存管理機制部分:多線程

運行時數據區分爲:程序計數器、虛擬機棧、本地方法棧、方法區、堆。其中程序計數器、虛擬棧、本地方法棧是線程隔離的,方法區、堆是線程共享的。併發

程序計數器:當前線程所執行的字節碼和行號指示器。若當前執行的是一個Java方法,這個計數器記錄的是正在執行的虛擬機的字節碼指令地址,若執行的是Native方法這個計數器爲空。此區域是惟一沒有規定任何OOM Error狀況的區域。函數

虛擬機棧:描述Java方法執行的內存模型,每一個方法執行時會建立一個棧幀,用於存儲局部變量表、操做數棧、動態連接、方法出口等信息。棧的深度分爲固定的和可動態擴展的,若棧深度固定,當線程請求大於虛擬機容許深度拋出StackOverflowError異常,如果動態擴展的,當擴展到沒法申請足夠內存時拋出OutOfMemoryError異常。spa

本地方法棧:與虛擬機棧相似,只不過是爲Native方法服務的。也會拋出StackOverflowError異常和OutOfMemoryError異常。線程

堆:JVM管理的內存中最大的一塊區域,建立實例和GC操做在這個區,分爲新生代、老年代。實例分配過多沒法擴展時拋出OOM Error異常。對象

方法區:用於存放類信息、常量、靜態變量、即時編譯器編譯後的代碼等數據。JDK 1.7以前將方法區做爲"永生代"做爲堆的一部分,這樣GC操做也能清理這個區域,但因爲方法區的清理效率很低,很容易形成OOM Error的BUG,因此在JDK 1.7開始去除了永生代將方法區做爲非堆的一部分。這個區域包括了運行時常量池。隊列

直接內存:不是虛擬機運行時數據區的一部分,但被頻繁使用。NIO的I/O方式使用Native函數庫直接分配對外內存。配置虛擬機忽略直接內存時,使得內存區域大於物理內存會致使OOM Error異常。內存

 

垃圾收集器與內存分配策略部分資源

判斷對象是否「已死」的方法有:A.引用計數法,被引用時計數加一,取消引用時計數減一,爲零時判爲已死。優勢是簡單高效,缺點存在循環引用的問題。B.可達性分析方法:從GC Root(虛擬機棧中的引用的對象、方法區中類靜態屬性引用的對象、方法區中常量引用的對象、本地方法棧中JNI引用的對象。)的可達樹向下遍歷,最後不可達的對象就是已死的。
「已死」對象並不會當即死亡:當經過GC Root判斷不可達會被標記一個「死亡」標記,而後進行一次篩選,若標記了「死亡」標記的對象沒有必要執行的finalize方法(沒有覆蓋finalize()方法或finalize()已被執行),則會進行第二次標記並進行回收,不然將此對象放入一個隊列,執行隊列裏全部對象的finallize方法(不必定等該方法執行完)。在這個finalize方法中對象能夠作一些復活的操做(好比從新連上引用,但不建議),若該對象復活則移出隊列,以後再進行第二次標記操做時,而後被回收。

方法區被用做永生代時能夠被GC,可是方法區的GC性價比很低,效率很低(JDK 1.7的JVM不在將方法區用做永生代)。回收時通常回收廢棄的常量和無用的類(該類實例已被回收、類加載器被回收、Class對象沒被其餘任何地方引用)

垃圾回收算法:

A.標記-清除算法:最基礎的回收算法,標記可回收的對象再清楚,缺點效率低容易產生碎片。

B.複製算法:將內存分配大小一致的兩塊,用的時候只用其中一塊另外一塊保留,當這一塊用完之後將仍存活的對象對齊複製到另外一保留塊上,清理原來塊上的內存,簡單高效但內存代價過高。此爲新生代回收算法,將內存分爲較大的Eden空間和兩塊較小的Survivor空間,回收時將Eden和其中一塊Survivor存活的對象複製到另外一塊Survivor上,若另外一塊Survivor裝不下就轉移到老年代中。

C.標記-整理算法:是將可回收對象標記之後對存活對象進行整理,在對邊界的標記對象進行清理,解決碎片問題。

D.分代收集算法:年輕代對象很快死去故使用複製算法,老年代不容易死去使用標記-清理或者標記-整理算法。

垃圾收集器:

A.Serial收集器:「單線程「的新生代收集器,要停下全部的用戶線程,而後專門進行收集,雖然要停頓,可是在不復雜狀況下暫可接受。

B.ParNew收集器:即Serial的多線程版本,也是新生代收集器,仍要停掉全部用戶線程而後開啓多個線程進行垃圾收集,能CMS收集器配合工做。

C.Parallel Scavenge 收集器:與ParNew收集器類似,不一樣點是Parallel Scavenge能夠設置自適應調節策略看控制吞吐量。

D.Serial Old收集器:Serial的老年代版本。

E.Parallel Old收集器:Parallel Scavenge的老年代版本。

F.CMS收集器(Concurrent Mark Sweep):基於標記-清楚,以最短的回收停頓,分爲初始標記(要暫停全部用戶線程並單線程標記GC Root)、併發標記(能夠和用戶線程併發進行GC Root Trace)、從新標記(暫停全部用戶線程並多線程修正一些標記)、併發清理(與用戶線程併發進行)四個階段,缺點:對CPU資源敏感、沒法處理浮動垃圾、會產生碎片。

G.G1收集器:工做在整個堆上,不分新生代和老年代而是將對分爲不少個Region(每一個Region中也有新生代和老年代的概念)根據每一個Region的垃圾堆積的價值大小進行回收,優先回收最大的Region。分爲初試標記(停用戶線程的單線程)、併發標記、最終標記(聽用戶的多線程)、篩選回收(停用戶的多線程)四個階段。具備並行與併發、分帶手機、空間整合、可預測停頓等特色。

相關文章
相關標籤/搜索