對象分配原則
- 對象優(yōu)先分配在Eden區(qū),如果Eden區(qū)沒有足夠的空間時度帮,虛擬機執(zhí)行一次Minor GC腺办。
- 大對象直接進入老年代(大對象是指需要大量連續(xù)內(nèi)存空間的對象)藻雌。這樣做的目的是避免在Eden區(qū)和兩個Survivor區(qū)之間發(fā)生大量的內(nèi)存拷貝(新生代采用復(fù)制算法收集內(nèi)存)
- 長期存活的對象進入老年代。虛擬機為每個對象定義了一個年齡計數(shù)器吨掌,如果對象經(jīng)過了1次Minor GC那么對象會進入Survivor區(qū)半抱,之后每經(jīng)過一次Minor GC那么對象的年齡加1,知道達到閥值對象進入老年區(qū)
- 動態(tài)判斷對象的年齡膜宋。如果Survivor區(qū)中相同年齡的所有對象大小的總和大于Survivor空間的一半窿侈,年齡大于或等于該年齡的對象可以直接進入老年代
- 空間分配擔(dān)保。每次進行Minor GC時秋茫,JVM會計算Survivor區(qū)移至老年區(qū)的對象的平均大小史简,如果這個值大于老年區(qū)的剩余值大小則進行一次Full GC,如果小于檢查HandlePromotionFailure設(shè)置肛著,如果true則只進行Monitor GC,如果false則進行Full GC
類加載器
- 啟動類加載器:Bootstrap ClassLoader圆兵,負責(zé)加載存放在JDK\jre\lib(JDK代表JDK的安裝目錄跺讯,下同)下,或被-Xbootclasspath參數(shù)指定的路徑中的殉农,并且能被虛擬機識別的類庫
- 擴展類加載器:Extension ClassLoader刀脏,該加載器由sun.misc.Launcher$ExtClassLoader實現(xiàn),它負責(zé)加載DK\jre\lib\ext目錄中超凳,或者由java.ext.dirs系統(tǒng)變量指定的路徑中的所有類庫(如javax.*開頭的類)愈污,開發(fā)者可以直接使用擴展類加載器
- 應(yīng)用程序類加載器:Application ClassLoader,該類加載器由sun.misc.Launcher$AppClassLoader來實現(xiàn)聪建,它負責(zé)加載用戶類路徑(ClassPath)所指定的類钙畔,開發(fā)者可以直接使用該類加載器
Java對象結(jié)構(gòu)
Java對象由三個部分組成:對象頭、實例數(shù)據(jù)金麸、對齊填充擎析。
對象頭由兩部分組成,第一部分存儲對象自身的運行時數(shù)據(jù):哈希碼挥下、GC分代年齡揍魂、鎖標識狀態(tài)、線程持有的鎖棚瘟、偏向線程ID(一般占32/64 bit)现斋。第二部分是指針類型,指向?qū)ο蟮念愒獢?shù)據(jù)類型(即對象代表哪個類)偎蘸。如果是數(shù)組對象庄蹋,則對象頭中還有一部分用來記錄數(shù)組長度。
實例數(shù)據(jù)用來存儲對象真正的有效信息(包括父類繼承下來的和自己定義的)
對齊填充:JVM要求對象起始地址必須是8字節(jié)的整數(shù)倍(8字節(jié)對齊)
如何判斷對象可以被回收迷雪?
判斷對象是否存活一般有兩種方式:
- 引用計數(shù):每個對象有一個引用計數(shù)屬性限书,新增一個引用時計數(shù)加1,引用釋放時計數(shù)減1章咧,計數(shù)為0時可以回收倦西。此方法簡單,無法解決對象相互循環(huán)引用的問題赁严。
- 可達性分析(Reachability Analysis):從GC Roots開始向下搜索扰柠,搜索所走過的路徑稱為引用鏈。當(dāng)一個對象到GC Roots沒有任何引用鏈相連時疼约,則證明此對象是不可用的卤档,不可達對象。
JVM的永久代中會發(fā)生垃圾回收么程剥?
垃圾回收不會發(fā)生在永久代裆装,如果永久代滿了或者是超過了臨界值,會觸發(fā)完全垃圾回收(Full GC)。如果你仔細查看垃圾收集器的輸出信息哨免,就會發(fā)現(xiàn)永久代也是被回收的茎活。這就是為什么正確的永久代大小對避免Full GC是非常重要的原因。請參考下Java8:從永久代到元數(shù)據(jù)區(qū) (注:Java8中已經(jīng)移除了永久代琢唾,新加了一個叫做元數(shù)據(jù)區(qū)的native內(nèi)存區(qū))
引用分類
- 強引用 : GC時不會被回收
- 軟引用 : 描述有用但不是必須的對象载荔,在發(fā)生內(nèi)存溢出異常之前被回收
- 弱引用 : 描述有用但不是必須的對象,在下一次GC時被回收
- 虛引用(幽靈引用/幻影引用) : 無法通過虛引用獲得對象采桃,用PhantomReference實現(xiàn)虛引用懒熙,虛引用用來在GC時返回一個通知
OutOfMemoryError異常
- (堆) Java對用于存儲對象實例,只要不斷的創(chuàng)建對象普办,并保證避免垃圾回收機制清除這些對象工扎,那么對象數(shù)量達到最大堆的容積之后就會內(nèi)存溢出
- (虛擬機棧、本地方法棧) 虛擬機在擴展棧時無法申請到足夠的內(nèi)存空間
- (運行時常量池) list.add(String.valueOf(i++).intern())衔蹲,提示信息是"PermGen space"
- (方法區(qū)) 運行時產(chǎn)生大量的類去填滿方法區(qū)肢娘,直到溢出
- (本機直接內(nèi)存) Unsafe.allocateMemory()
垃圾收集算法
算法 | 描述 | 優(yōu)點 | 缺點 |
---|---|---|---|
標記-清除 | 首先標記出所有需要回收的對象,在標記 完成后統(tǒng)一回收掉所有被標記的對象 | 最基礎(chǔ)的收集算法 | 1.效率不高2.標記清除之后會 產(chǎn)生大量不連續(xù)的內(nèi)存碎片 |
復(fù)制 | 將可用的內(nèi)存容量劃分為兩個大小相等的兩塊舆驶, 每次只使用其中一塊橱健。當(dāng)這一塊的內(nèi)存使用完, 就將還存活的對象復(fù)制到另外一塊沙廉,然后將 已使用過的一次清理掉拘荡,適用于新生代 | 1.每次都是對半?yún)^(qū)進行內(nèi)存回收, 內(nèi)存分配時也不需要考慮內(nèi)存碎片等復(fù)雜情況 2.只需要移動堆頂指針撬陵,按順序分配內(nèi)存即可 3.實現(xiàn)簡單珊皿,運行高效 | 1.將內(nèi)存縮小為原來的一半,代價高 2.在對象存活率較高時就要進行較多 的復(fù)制操作巨税,效率將會變低 |
標記-整理 | 先標記出所有需要回收的對象蟋定,然后讓所有存 活的對象都想一端移動,然后直接清理掉端邊 界以外的內(nèi)存 | 適用于對象存活率高老年代 | |
分代收集算法 | 把Java堆分成新生代和老年代垢夹,根據(jù)各個年代 的特點采用最適當(dāng)?shù)氖占惴āP律捎脧?fù)制维费, 老年代采用標記-清除或標記-整理 |
垃圾收集器
- Serial收集器果元,最基本最古老的收集器,是一個單線程的收集器犀盟,可能產(chǎn)生較長時間的停頓而晒。Client模式下的虛擬機默認新生代的收集器
- ParNew收集器,ParNew是Serial收集器的多線程版本阅畴。ParNew收集器在單CPU的環(huán)境中絕對不會有比Serial收集器更好的效果倡怎。它默認開啟的收集線程數(shù)與CPU數(shù)量相同,在CPU非常多的情況下,可以用-XX:ParallelGCThreads參數(shù)限制垃圾收集的線程
- Parallel Scavenge收集器监署,是一個新生代收集器颤专、采用復(fù)制算法、并行的多線程收集器钠乏。Parallel Scavenge收集器的目的是達到一個可控制的吞吐量栖秕,吞吐量=運行用戶代碼時間/(運行用戶代碼時間+垃圾收集時間)
- Serial Old收集器,是Serial收集器的老年代版本晓避,同樣是一個單線程收集器簇捍,使用"標記-整理"算法
- Parallel Old收集器,是Parallel Scavenge收集器的老年代版本俏拱,使用多線程和"標記-整理"算法
- CMS(Concurrent Mark Sweep)收集器暑塑,是一種以獲取最短回收停頓時間為目標的收集器」兀基于"標記-清除"算法事格,整個過程分為4步:
- 初始標記 (CMS initial mark)
- 并發(fā)標記 (CMS concurrent mark)
- 重新標記 (CMS remark)
- 并發(fā)清除 (CMS concurrent sweep)
其中,初始標記况毅、重新標記這兩個步驟仍然需要"Stop The World"分蓖。初始標記僅僅只是標記一下GC Roots能直接關(guān)聯(lián)到的對象,速度很快尔许;并發(fā)標記就是進行GC Roots Tracing定位么鹤,而重新標記是為了修正并發(fā)標記期間用戶程序繼續(xù)運作而導(dǎo)致標記產(chǎn)生變動的那一部分對象的標記記錄。
整個過程中耗時最長的并發(fā)標記和并發(fā)清除都是跟用戶線程一起工作味廊,所以蒸甜,從總體上來說,CMS收集器內(nèi)存回收是與用戶線程一起并發(fā)執(zhí)行的
缺點
- CMS收集器對CPU資源非常敏感余佛。CMS默認啟動的回收線程數(shù)是(CPU數(shù)量+3)/4
- CMS收集器無法處理浮動垃圾柠新,可能出現(xiàn)"Concurrent Mode Failure"失敗而導(dǎo)致另一次Full GC的產(chǎn)生
- G1收集器,G1 (Garbage-First)是一款面向服務(wù)器的垃圾收集器,主要針對配備多顆處理器及大容量內(nèi)存的機器. 以極高概率滿足GC停頓時間要求的同時,還具備高吞吐量性能特征
- 初始標記 (Initial Marking)
- 并發(fā)標記
- 最終標記
- 篩選回收