綠色的爲線程私有,橘色的爲線程共有java
負責將.class
文件加載到內存中,而且將該文件中的數據結構轉換爲方法區中的數據結構,生成一個Class
對象算法
自啓動類加載器。Bootstrap ClassLoader
類加載器。負責加載jdk
自帶的包。安全
%JAVA_HOME%/lib/rt.jar%
即JDK源碼C++
編寫null
擴展類加載器.Extension ClassLoader
。負責加載jdk
擴展的包服務器
%JAVA_HOME/lib/ext/*.jar%
應用類加載器或系統類加載器。AppClassLoader或SystemClassLOader
數據結構
CLASSPATH
路徑下自定義類加載器多線程
ClassLoader
抽象類實現當應用類加載器獲取到一個類加載的請求的時候,不會當即處理這個類加載請求,而是將這個請求委派給他的父加載器加載,若是這個父加載器不可以處理這個類加載請求,便將之傳遞給子加載器。一級一級傳遞指導能夠加載該類的類加載器。架構
該機制又稱沙盒安全機制。防止開發者對JDK
加載作破壞併發
loadClass
方法sun.misc.Launcher
類函數
執行引擎負責執行解釋命令,交給操做系統進行具體的執行性能
native
方法指Java
層面不能處理的操做,只能經過本地接口調用本地的函數庫(C函數庫
)
一套調用函數庫的接口
在加載native
方法的時候,會將執行的C
函數庫的方法,放在這個棧區域執行
每一個線程都有程序計數器,主要做用是存儲代碼指令,就相似於一個執行計劃。
內部維護了多個指針,這些指針指向了方法區中的方法字節碼。執行引擎從程序計數器中獲取下一次要執行的指令。
因爲空間很小,他是當前線程執行代碼的一個行號指示器/
不會引起OOM
供各線程共享的運行時內存區域,存放了各個類的結構信息(一個Class對象),包括:字段,方法,構造方法,運行時常量池。
雖然JVM規範將方法區描述爲堆的一個邏輯部分,但它卻還有一個別名叫作Non-Heap(非堆),目的就是要和堆分開
主要有:永久代或者元空間。存在GC
元空間中因爲直接使用物理內存的影響,因此默認的最大元空間大小爲1/4
物理內存大小
主要負責執行各類方法,是線程私有的,隨線程的消亡而消亡,不存在垃圾回收的問題。八大數據類型和實例引用都是在函數的棧內存中分配內存的。
默認大小爲512~1024K
,經過-Xss1024k
參數修改
棧FILO
:先進後出
隊列FIFO
:先進先出
Local Variable
。包括方法的形參和返回值Operand Stack
。包括各類壓棧和出棧操做Frame Data
。就至關於一個個方法。在棧空間中,方法被稱爲棧幀棧中執行的單位是棧幀,棧幀就是一個個方法。
main
方法壓棧,成爲一個棧幀256K~756K
默認初始大小爲物理內存的1/64
,默認最大大小爲1/4
。在實際生產中通常會將這兩個值設置爲相同,避免垃圾回收器執行完垃圾回收之後還須要進行空間的擴容計算,浪費資源。
堆外內存:內存對象分配在Java虛擬機的堆之外的內存,這些內存直接受操做系統管理(而不是虛擬機),這樣作的結果就是可以在必定程度上減小垃圾回收對應用程序形成的影響。使用未公開的Unsafe和NIO包下ByteBuffer
來建立堆外內存。
默認的堆外內存大小爲,經過-XX:MaxDirectMemorySize=
執行堆外內存的大小
在邏輯上劃分爲三個區域:
新生區Young Generation Space
。
Eden Space
Survivor 0 Space
Survivor 1 Space
Tenure Generation Space
Permanent Space
(方法區)在物理層面劃分爲兩個區域:
主要流程有三步:
Eden
滿了之後出發一次輕GC(Minor GC
),沒有死亡的對象,年齡+1
,存放到from
區域Eden
再次滿了之後再次觸發一次GC
,沒有死亡的對象放置於to
區域,而後將from
區域中沒有死亡的對象所有置於to
區域,年齡+1
。以後每一次GC都會出發一次from
和to
的交換,哪一個區域是空的那個區域就是to
當survivor
區域滿了之後,再次觸發GC,當存在對象的年齡等於15
的時候,就會將該對象移入老年區
MaxTenuringThreshold
經過這個參數設置當年齡爲多少的時候移入Full GC
,若是老年區沒法再存放對象直接報OOM
注意:每一次GC都會給存活的對象的年齡+1
和1.7
相比,僅僅是將永久代更替爲了元空間。元空間的存放內置是物理內存,而不是JVM
中。
這樣處理,可使元空間的大小再也不受虛擬機內存大小的影響,而是由系統當前可用的空間來控制。
新生區和老年區的大小比例爲1:2
,經過-XX:NewRatio=n
設置新生代和老年代的比例,n表明老年區所佔的比例。
Eden Space和Survivor Space之間的比例默認爲8:1
,經過-XX:SurvivorRatio
設置伊甸區和倖存者區的比例
邏輯層面分層:
新生區Young Generation Space
Eden Space
Survivor 0 Space
Survivor 1 Space
Tenure Generation Space
物理層面分層:
參數 | 做用 |
---|---|
-Xms | 設置初始堆大小,默認爲物理內存的1/64 |
-Xmx | 設置最大堆大小,默認爲物理內存的1/4 |
-XX:+PrintGCDetails | 輸出詳細的GC日誌 |
模擬OOM
//設置最大堆內存爲10m //-Xms10m -Xmx10m -XX:+PrintGCDetails
下面咱們具體分析一下GC的過程作了什麼,GC日誌怎麼看
名稱:GC之前佔用->GC以後佔用(總共佔用)
//GC 分配失敗 GC (Allocation Failure) [PSYoungGen: 1585K->504K(2560K)] 1585K->664K(9728K), 0.0009663 secs] //[新生代,之前佔用->線程佔用(總共空閒)] 堆使用大小->堆如今大小(總大小) [Times: user=0.00 sys=0.00, real=0.00 secs] [Full GC (Allocation Failure) [PSYoungGen: 0K->0K(2560K)] [ParOldGen: 590K->573K(7168K)] 590K->573K(9728K), [Metaspace: 3115K->3115K(1056768K)], 0.0049775 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
minor GC
)發生在新生區的,很頻繁major GC
發生在老年代的垃圾收集動做,出現一次major GC
常常會伴隨至少一次的Minor GC
主要思想:每存在一個對象引用就給這個對象加一,當這個對象的引用爲零的時候,便觸發垃圾回收。通常不使用
缺點:
主要思想:將對象直接拷貝一份,放置到其餘區域
優勢:不會產生內存碎片
缺點:佔用空間比較大
使用場景:新生區的複製就是經過複製算法來執行的。當Minor Gc
之後,就會倖存的對象複製一份放置到to
區
主要思想:從引用根節點遍歷全部的引用,標記出全部須要清理的對象,而後進行清除。兩步完成
缺點:在進行垃圾回收的時候會打斷整個代碼的運行。會產生內存碎片
主要思想:和標記清除算法同樣,最後添加了一個步驟整理,將整理內存碎片。三步完成
缺點:效率低,須要移動對象。
複製算法>標記清除法>標記整理法
複製算法=標記整理法>標記清除法
標記整理法=標記清除法>複製算法
經過場景使用不一樣的算法,來達到最優的目的
年輕代:由於其對象存活時間段,對象死亡率高,因此通常使用複製算法
老年代:區域大,存活率高,通常採用標記清除和標記整理的混合算法。
老年代通常是由標記清除或者是標記清除與標記整理的混合實現。以hotspot中的CMS回收器爲例,CMS是基於Mark-Sweep實現的,對於對像的回收效率很高,而對於碎片問題,CMS採用基於Mark-Compact算法的Serial Old回收器作爲補償措施:當內存回收不佳(碎片致使的Concurrent Mode Failure時),將採用Serial Old執行Full GC以達到對老年代內存的整理。
上面咱們提到標記清除算法的時候,提到了一個名詞,根節點引用。那麼什麼叫作根節點引用呢?
根節點引用也成GCRoots
,他是指垃圾回收算法進行對象遍歷的根節點。即從這個對象開始往下遍歷,標記須要進行回收的對象。
垃圾回收標記的過程就是:以GCRoots
對象開始向下搜索,若是一個對象到GCRoots
沒有任何的引用鏈相連時,說明此對象不可用。
就是從GCRoots
進行遍歷,能夠被遍歷到的就不是垃圾,沒有被遍歷到的就是垃圾,斷定死亡
可達性對象是指,在對象鏈路引用的頂層是一個GCRoot
引用
不可達對象是指,在對象鏈路引用的頂層不是一個GCRoot
引用
通俗解釋:可達性對象就是對象有一個歸屬,這個歸屬有一個術語名稱叫作GCRoot
,不可達性對象就是這些對象沒有歸屬。
native
修飾的方法說白了,就是全部暴露給開發者的引用
垃圾回收器是基於GC
算法實現的。
主要有四種垃圾回收器,不過具體有七種使用方式
單線程進行垃圾回收,此時其餘的線程所有被暫停
經過-XX:+UseSerialGC
多線程進行垃圾回收,此時其餘的線程所有被暫停
GC線程和用戶線程同時運行
分區垃圾回收。物理上不區分新生區和養老區,將堆內存劃分爲1024
個小的region
,每個佔據的空間在2~32M
,每個region
均可能是Eden Space
、Survivor01 Space
、Survivor02 Space
和Old
區。
總體使用了標記整理算法,局部使用了複製算法。經過複製算法將GC後的對象從一個region
向另外一個region
遷移,至於形成了內存碎片問題,經過總體的標記整理算法,避免了內存碎片的誕生
在進行垃圾回收的時候直接對一個region
進行回收,保存下來的對象經過複製算法複製到TO
區或者Old
區。
邏輯上堆有四個區,每個區的大小不定,按需分配。分爲Eden Space
,Survivor01 Space
,Old
和Humongous
。其中Humongous
用來存放大對象,通常是連續存儲,當因爲連續region
不足的時候,會觸發Full GC
清理周圍的Region
以存放大對象
G1堆內存示意
G1垃圾回收
出現大對象,三個region不能存放,進行FullGC
執行流程
GCRoots
GCRoots
的全部的對象,進行標記Full GC
-XX:+UseG1GC 開啓GC -XX:G1HeapRegionSize=n : 設置G1區域的大小。值是2的冪,範圍是1M到32M。目標是根據最小的Java堆大小劃分出約2048個區域 -XX:MaxGCPauseMillis=n : 最大停頓時間,這是個軟目標,JVM將盡量(但不保證)停頓時間小於這個時間 -XX:InitiatingHeapOccupancyPercent=n 堆佔用了多少的時候就觸發GC,默認是45 -XX:ConcGCThreads=n 併發GC使用的線程數 -XX:G1ReservePercent=n 設置做爲空閒空間的預留內存百分比,以下降目標空間溢出的風險,默認值是10%
DefNew Default New Generation //串行垃圾回收器,新生代叫法 Tenured Old //串行垃圾回收器,老年代叫法 ParNew Parallel New Generation //新生代並行垃圾回收器,新生代叫法 PSYongGen Parallel Scavenge //新生代和老年代垃圾回收器,叫法 ParOldGen Parallel Old Generation //新生代和老年代垃圾回收器,叫法
上圖顯示的是新生區和老年區可使用垃圾回收器的全部種類,咱們一個一個來講明
新生代使用Serial Coping
垃圾回收器使用複製算法
老年區默認使用Serial Old
垃圾回收器,使用標記清除算法和標記整理算法
經過-XX:+UseSerialGC
設置
新生區使用ParNew
垃圾回收器,使用複製算法
老年區使用Serial Old
垃圾回收器(不推薦這樣使用),使用標記清除算法和標記整理算法
經過-XX:+UseParNewGC
啓動
新生代使用並行垃圾回收
老年代使用並行垃圾回收。Java1.8中默認使用的垃圾回收器
一個問題:Parallel和Parallel Scavenge收集器的區別?
Parallel Scavenge
收集器相似於ParNew
也是一個新生代的垃圾收集器,使用了複製算法,也是一個並行的多線程的垃圾收集器,俗稱吞吐量優先收集器。
parallel Scavenge
是一種自適應的收集器,虛擬機會根據當前系統運行狀況收集性能監控信息,動態調整這些參數以提供最合適的提頓時間或者最大吞吐量
他關注的點是:
可控制的吞吐量。吞吐量=運行用戶代碼時間/(運行用戶代碼時間+垃圾收集時間),
同時,當新生代選擇爲Parallel Scavenge
的時候,會默認激活老年區使用並行垃圾回收
經過-XX:UseParallelGC或者-XX:UseParallelOldGC
二者會互相激活
-XX:ParallelGCThreads=n
表示啓動多少個GC線程
cpu>8時 N=5或者8
cpu<8時 N=實際個數
Serial Old
是Serial
垃圾收集器老年代版本,是一個單線程的收集器,使用標記整理算法,運行在Client
中的年老代垃圾回收算法
與新生代的Serial GC
相關聯
Parallel Old/
採用標記整理算法實現
與新生代的Parallel Scavenge GC
相關聯
CMS
收集器(Concurrent Mark Sweep
併發標記清除):一種以獲取最短回收停頓時間爲目標的收集器
適合應用在互聯網站或者B/S
系統的服務器上,重視服務器的響應速度
CMS
很是適合堆內存大、CPU
核數多的服務端應用,也是G1
出現以前大型應用的首選收集器
標記的時候,GC線程運行;清除的時候和用戶線程一塊兒運行
經過-XX:+UseConcMarkSweepGC
指令開啓
配合新生區的pallellal New GC
回收器使用
當CMS因爲CPU壓力太大沒法使用的時候會使用SerialGC
做爲備用收集器
CMS initial mark
)。遍歷尋找到全部的GCRoots
。GC
線程執行,用戶線程暫停CMS concurrent mark
)和用戶線程一塊兒遍歷GCRoots
,標記須要清除的對象CMS remark
)。修正標記期間,對因用戶程序繼續運行而不須要進行回收的對象進行修正CMS concurrent sweep
)和用戶線程一塊兒清除全部標記的對象優勢:
缺點:
參數(-XX:+……) | 新生代垃圾回收器 | 新生代算法 | 老年代垃圾回收器 | 老年代算法 |
---|---|---|---|---|
UseSerialGC | SerialGC | 複製算法 | Serial Old GC | 標整 |
UseParNewGC | Parallel New GC | 複製算法 | Serial Old GC | 標整 |
UseParllelGC | Parallel Scavenge GC | 複製算法 | Parallel GC | 標整 |
UseConcMarkSweepGC | Parallel New GC | 複製算法 | CMS和Serial Old GC | 標清 |
UseG1GC | 總體標整 | 局部複製 |
垃圾回收算法通用邏輯
java內存模型。是一種規範。
線程在操做變量的時候,首先從物理內存中複製一份到本身的工做內存中(棧內存),更新之後再寫入物理內存中
特色:
更多原創文章和學習教程請關注筆者同名公衆號@MakerStack獲取