摘要:虛擬機棧區(qū)也就是通常所說的棧區(qū),它描述的是方法執(zhí)行的內(nèi)存模型,每個方法被執(zhí)行的時候都創(chuàng)建一個棧幀,用于存儲局部變量表操作數(shù)棧動態(tài)鏈接方法出口等。每個方法被調(diào)用到完成,相當于一個棧幀在虛擬機棧中從入棧到出棧的過程。
一.JVM 內(nèi)存結構大多數(shù)情況下我們對GC的了解都只是淺層含義上的,下面我們來詳細講解下內(nèi)部的一些實現(xiàn)原理。
講解GC之前,我們得先了解下JVM的內(nèi)存結構,才能讓我們理解GC導致是干嘛的。
JVM內(nèi)存結構由5個部分組成,分別如下
1. 程序計數(shù)器(Program Conuter Register)一塊較小的內(nèi)存空間,它是當前線程執(zhí)行字節(jié)碼的行號指示器,字節(jié)碼解釋工作器就是通過改變這個計數(shù)器的值來選取下一條需要執(zhí)行的指令。它是線程私有的內(nèi)存,也是唯一一個沒有OOM異常的區(qū)域。
2. Java虛擬機棧區(qū)(Java Virtual Machine Stacks)也就是通常所說的棧區(qū),它描述的是Java方法執(zhí)行的內(nèi)存模型,每個方法被執(zhí)行的時候都創(chuàng)建一個棧幀(Stack Frame),用于存儲局部變量表、操作數(shù)棧、動態(tài)鏈接、方法出口等。每個方法被調(diào)用到完成,相當于一個棧幀在虛擬機棧中從入棧到出棧的過程。此區(qū)域也是線程私有的內(nèi)存,可能拋出兩種異常:如果線程請求的棧深度大于虛擬機允許的深度將拋出StackOverflowError;如果虛擬機棧可以動態(tài)的擴展,擴展到無法動態(tài)的申請到足夠的內(nèi)存時會拋出OOM異常。
3. 本地方法棧(Native Method Stacks)本地方法棧與虛擬機棧發(fā)揮的作用非常相似,區(qū)別就是虛擬機棧為虛擬機執(zhí)行Java方法,本地方法棧則是為虛擬機使用到的Native方法服務。
4. 堆區(qū)(Heap)所有對象實例和數(shù)組都在堆區(qū)上分配,堆區(qū)是GC主要管理的區(qū)域。堆區(qū)還可以細分為新生代、老年代,新生代還分為一個Eden區(qū)和兩個Survivor區(qū)。此塊內(nèi)存為所有線程共享區(qū)域,當堆中沒有足夠內(nèi)存完成實例分配時會拋出OOM異常。
5. 方法區(qū)(Method Area)方法區(qū)也是所有線程共享區(qū),用于存儲已被虛擬機加載的類信息、常量、靜態(tài)變量、即時編譯后的代碼等數(shù)據(jù)。GC在這個區(qū)域很少出現(xiàn),這個區(qū)域內(nèi)存回收的目標主要是對常量池的回收和類型的卸載,回收的內(nèi)存比較少,所以也有稱這個區(qū)域為永久代(Permanent Generation)的。當方法區(qū)無法滿足內(nèi)存分配時拋出OOM異常。
二.GC 原理1. 什么時候回收?針對GC的原理機制,主要搞清楚下面三個問題。
什么時候回收?
哪些需要回收?
怎么回收?
1.對象優(yōu)先分配到新生代的Eden區(qū),當不夠空間的時候進行一次Minor GC,清理頻率很高。
2.Full GC發(fā)生在老年代,當不夠空間的時候進行一次Full GC,伴隨著也會進行一次Minor GC。
3.進行Minor GC時,會判斷每次變成晉升到老年代的對象平均值是否大于老年代剩余空間,如果大于,則進行一次Full GC,如果小于就會去判斷HandlePromotionFailure設置是否允許擔保失敗,如果允許,則進行Minor GC,不允許則改為Full GC。
上面提到GC主要管理的是堆區(qū),堆區(qū)主要分為`新生代`和`老年代` * 【新生代】分為一個Eden和兩個Survivor區(qū)。新new的對象都放在這里,很快消亡。 * 【老年代】新new的大對象直接丟到這里(為了避免在Eden區(qū)和兩個Survivor區(qū)發(fā)生大量的內(nèi)存拷貝),其余就是在新生代多次回收沒被干掉過來變成老家伙的對象了。2. 哪些需要回收?
當調(diào)用了finalize()方法后,則需要進行清理,具體場景如上。
* 什么是finalize()方法? 每次進行GC之前系統(tǒng)都會調(diào)用一次finalize()方法,用以清理所有活動并且釋放資源。 * 什么時候調(diào)用finalize()方法? 1.GC調(diào)用之前,例如運行System.gc();(調(diào)用System.gc()只是建議JVM去執(zhí)行,是否執(zhí)行還得JVM去判斷) 2.程序退出時,每個對象都會調(diào)用finalzie 3.顯式調(diào)用finalize3. 怎么回收?
JVM會根據(jù)不同的收集器使用不同的算法組合來達到回收的效果
### 垃圾收集算法 * mark-sweep(標記-清除)- 標記所有需要回收的對象,在標記完成后統(tǒng)一回收這些對象。 缺點:1.標記和清除兩個過程的效率都不高。2.標記清除會產(chǎn)生大量不連續(xù)的內(nèi)存碎片。 * copying(復制)- 主要用來回收新生代 新生代分為一個Eden區(qū)、兩個Survivor區(qū)(Survivor0、Survivor1),Eden和Survivor默認8:1。回收時先把Eden存活對象復制到Survivor0區(qū),清空Eden區(qū),當Survivor0區(qū)滿了以后,把Eden和Survivor0區(qū)的存活對象復制到Survivor1區(qū),清空Eden區(qū)和Survivor0區(qū),之后交換Survivor0和Survivor1區(qū),保持Survivor1區(qū)是空的,如此往復 * mark-compact(標記-整理) 主要用來回收老年代。標記需要回收的對象,將其他存活的對象都向一端移動,然后直接清理掉端邊界以外的內(nèi)存。 * generational collection(分代) 目前常用的收集算法,區(qū)分新生代和老年代做不同的算法收集。針對新生代,只有少量存活,選用復制算法。針對老年代,存活率高,沒有額外的空間對它進行分配擔保,就必須使用“標記-清理”或者“標記-整理”算法來進行回收。 -------- ### 垃圾收集器 * Serial 、Serial Old 收集器 [-XX:+UseSerialGC,使用 Serial + Serial Old 組合回收] 適合單處理器系統(tǒng),并且在進行垃圾回收的時候會暫停其他所有的工作線程(stop the world),對于多處理器的系統(tǒng)來說是災難 * ParNew 收集器 [-XX:UseParallelGC,使用 Parallel Scavenge + Serial Old 組合回收] serial 收集器的多線程版本。ParNew是許多運行在Server模式下的虛擬機中首選的新生代收集器,除了Serial收集器外,只有它能與CMS收集器配合工作 * Parallel Scavenge 、Parallel Old 收集器 [-XX:GCTimeRatio,-XX:MaxGCPauseMillis] 通過兩個參數(shù)GCTimeRatio和MaxGCPauseMillis,盡可能縮短垃圾收集器用戶線程的停頓時間,從而達到一個可控制的吞吐量。 * CMS (Concurrent Mark Sweep)收集器 [-XX:UseConcMarkSweepGC,使用 ParNew + CMS + Serial Old 組合回收] 以獲取最短回收停頓時間為目標的收集器。 步驟 1.初始標記(CMS initial mark),標記GC Roots能直接關聯(lián)到的對象,速度很快 2.并發(fā)標記(CMS concurrent mark),進行GC Roots Tracing 3.重新標記(CMS remark),重新標記階段是為了修正并發(fā)標記期間因用戶程序繼續(xù)運作而導致變動的標記記錄,比并發(fā)標記時間短 4.并發(fā)清除(CMS concurrent sweep)并行刪除 缺點 1. 比較消耗CPU資源,默認啟動回收線程數(shù)是(CPU數(shù)量+3)/4。 2. CMS收集器無法處理浮動垃圾(CMS清理階段用戶線程還運行著,伴隨生成的新垃圾只能在下次GC再清理掉),可能出現(xiàn)“Concurrent Mode Failure”而導致另一次Full GC的產(chǎn)生。可以通過-XX:CMSInitiatingOccupancyFraction來調(diào)節(jié)。 3. 標記-清除會導致內(nèi)存碎片而導致觸發(fā)Full GC(切換到Serial Old收集器收集老年代)。可以通過-XX:UseCMSCompactAtFullCollection、-XX:CMSFullGCsBeforeCompaction來調(diào)節(jié)。 * G1(Garbage-First) 收集器 [-XX:+UseG1GC] Java堆的內(nèi)存分布和其他收集器有很大不同,它將整個Java堆劃分為多個大小相等的獨立區(qū)域`Region`,老年代和新生代不再物理隔離,而是一部分`Region`的集合。G1設計初衷是為了縮短大堆(>4GB)時的停頓時間。它會跟蹤各個Region的垃圾堆積價值大小,后臺維護一個優(yōu)先列表,每次根據(jù)允許的收集時間,優(yōu)先回收價值最大的`Region`。 特點 1.并發(fā)和并行 2.分代收集 3.空間整合 4.可預測的停頓 步驟 1.初始標記(Initial Marking) 2.并發(fā)標記(Concurrent Marking) 3.最終標記(Final Marking) 4.篩選回收(Live Data Counting and Evacuation)
補充:
1、并行Parallel-XX:+UseParalleGC,追求吞吐量
多條垃圾收集線程并行工作,但此時用戶線程仍然處于等待狀態(tài)
2、并發(fā)ConcurrentUseConcMarkSweepGC,追求響應速度
指用戶線程與垃圾收集線程同時執(zhí)行(但并不一定是并行的,可能會交替執(zhí)行),用戶程序在繼續(xù)運行,而垃圾收集程序運行于另一個CPU上
串行處理器: Serial
--適用情況:數(shù)據(jù)量比較小(100M左右);單處理器下并且對響應時間無要求的應用。
--缺點:只能用于小型應用
并行處理器:UseParalleGC
--適用情況:“對吞吐量有高要求”,多CPU、對應用響應時間無要求的中、大型應用。舉例:后臺處理、科學計算。
--缺點:應用響應時間可能較長
并發(fā)處理器:UseConcMarkSweepGC
--適用情況:“對響應時間有高要求”,多CPU、對應用響應時間有較高要求的中、大型應用。舉例:Web服務器/應用服務器、電信交換、集成開發(fā)環(huán)境。
文章版權歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/69869.html
摘要:基礎問題的的性能及原理之區(qū)別詳解備忘筆記深入理解流水線抽象關鍵字修飾符知識點總結必看篇中的關鍵字解析回調(diào)機制解讀抽象類與三大特征時間和時間戳的相互轉(zhuǎn)換為什么要使用內(nèi)部類對象鎖和類鎖的區(qū)別,,優(yōu)缺點及比較提高篇八詳解內(nèi)部類單例模式和 Java基礎問題 String的+的性能及原理 java之yield(),sleep(),wait()區(qū)別詳解-備忘筆記 深入理解Java Stream流水...
摘要:基礎問題的的性能及原理之區(qū)別詳解備忘筆記深入理解流水線抽象關鍵字修飾符知識點總結必看篇中的關鍵字解析回調(diào)機制解讀抽象類與三大特征時間和時間戳的相互轉(zhuǎn)換為什么要使用內(nèi)部類對象鎖和類鎖的區(qū)別,,優(yōu)缺點及比較提高篇八詳解內(nèi)部類單例模式和 Java基礎問題 String的+的性能及原理 java之yield(),sleep(),wait()區(qū)別詳解-備忘筆記 深入理解Java Stream流水...
摘要:基礎問題的的性能及原理之區(qū)別詳解備忘筆記深入理解流水線抽象關鍵字修飾符知識點總結必看篇中的關鍵字解析回調(diào)機制解讀抽象類與三大特征時間和時間戳的相互轉(zhuǎn)換為什么要使用內(nèi)部類對象鎖和類鎖的區(qū)別,,優(yōu)缺點及比較提高篇八詳解內(nèi)部類單例模式和 Java基礎問題 String的+的性能及原理 java之yield(),sleep(),wait()區(qū)別詳解-備忘筆記 深入理解Java Stream流水...
閱讀 664·2021-11-23 09:51
閱讀 3305·2021-10-11 10:58
閱讀 15465·2021-09-29 09:47
閱讀 3563·2021-09-01 11:42
閱讀 1293·2019-08-29 16:43
閱讀 1839·2019-08-29 15:37
閱讀 2112·2019-08-29 12:56
閱讀 1729·2019-08-28 18:21