天天看點

JVM記憶體區域劃分+垃圾機制

1.jdk,jre,jvm關系

三者是包含關系,如圖所示:
JVM記憶體區域劃分+垃圾機制

2.JVM的位置

JVM記憶體區域劃分+垃圾機制

什麼是JVM?

java virual machine,java虛拟機,是一種虛拟出來的計算機,運作在作業系統之上,屏蔽了具體作業系統平台的相關資訊,将位元組碼解釋成具體平台的機器指令執行,實作了java一次編譯,到處運作。

JVM體系包括:運作時資料區,類加載器,執行引擎等。

作業系統記憶體 和JVM記憶體

參考連結

JVM記憶體區域劃分+垃圾機制
JVM記憶體區域劃分+垃圾機制
JVM記憶體區域劃分+垃圾機制

當一個classLoder啟動的時候,classLoader的生存地點在jvm中的堆,然後它會去主機硬碟上将A.class裝載到jvm的方法區,方法區中的這個位元組檔案會被虛拟機拿來new A位元組碼(),然後在堆記憶體生成了一個A位元組碼的對象,然後A位元組碼這個記憶體檔案有兩個引用一個指向A的class對象,一個指向加載自己的classLoader

JVM記憶體區域劃分+垃圾機制

3.虛拟機運作時區域

以car類為例

總體結構圖:類生命周期&JVM記憶體區

JVM記憶體區域劃分+垃圾機制

4 JVM記憶體區域

JVM記憶體區域劃分+垃圾機制

4.1 程式計數器

程式計數器是每個線程私有的,是一塊較小的記憶體空間。可以看做是目前線程所執行位元組碼的行号訓示器,此記憶體區域沒有規定任何OutOfMemoryError情況的區域。
在虛拟機的概念模型裡(僅是概念模型,各種虛拟機可能 會通過一些更高效的方式去實作),位元組碼解釋器工作時就是通過改變這個計數器的值來選 取下一條需要執行的位元組碼指令,分支、循環、跳轉、異常處理、線程恢複等基礎功能都需 要依賴這個計數器來完成。
由于Java虛拟機的多線程是通過線程輪流切換并配置設定處理器執行時間的方式來實作的, 在任何一個确定的時刻,一個處理器(對于多核處理器來說是一個核心)都隻會執行一條線 程中的指令。是以,為了線程切換後能恢複到正确的執行位置,每條線程都需要有一個獨立 的程式計數器,各條線程之間計數器互不影響,獨立存儲,我們稱這類記憶體區域為“線程私 有”的記憶體。

如果線程正在執行的是一個Java方法,這個計數器記錄的是正在執行的虛拟機位元組碼指 令的位址;

如果正在執行的是Native方法,這個計數器值則為空(Undefined)。

4.2 虛拟機棧

== 線程私有的,生命周期與線程相同。==描述的是Java方法執行的記憶體模型:每個方法在執行的同時 都會建立一個棧幀(Stack Frame[1])用于存儲局部變量表、操作數棧、動态連結、方法出口 等資訊。每一個方法從調用直至執行完成的過程,就對應着一個棧幀在虛拟機棧中入棧到出 棧的過程。
在編譯程式代碼的時候,棧幀中需要多大的局部變量表,多深的操作數棧都已經完 全确定了,并且寫入到方法表的Code屬性之中[2],是以一個棧幀需要配置設定多少記憶體,不會受 到程式運作期變量資料的影響,而僅僅取決于具體的虛拟機實作。
在活動線程中,隻有位于棧頂的棧幀才是有效的,稱為目前棧幀(Current Stack Frame),與這個棧幀相關聯的方法稱為目前方法(Current Method)
JVM記憶體區域劃分+垃圾機制

方法執行 入棧出棧模型

public class demo{
public static void main(String[] args){
		add();

	}
		public void add(){
		update();
					.......
			}
		public  void update(){

           }
}
           
JVM記憶體區域劃分+垃圾機制

4.2.1 局部變量表

局部變量表的容量以變量槽(Variable Slot,下稱Slot)為最小機關。用于存放方法參數和方法 内部定義的局部變量。存放了編譯期可知的各種基本資料類型(boolean、byte、char、short、int、 float、long、double)、對象引用(reference類型,它不等同于對象本身,可能是一個指向對 象起始位址的引用指針,也可能是指向一個代表對象的句柄或其他與此對象相關的位置)和 returnAddress類型(指向了一條位元組碼指令的位址)。

對于64位的資料類型,虛拟機會以高位對齊的方式為其配置設定兩個連續的Slot空間。Java 語言中明确的(reference類型則可能是32位也可能是64位)64位的資料類型隻有long和double 兩種。其餘的資料 類型隻占用1個。==局部變量表所需的記憶體空間在編譯期間完成配置設定,==當進入一個方法時,這 個方法需要在幀中配置設定多大的局部變量空間是完全确定的,在方法運作期間不會改變局部變 量表的大小。

對這個區域規定了兩種異常狀況:

如果線程請求的棧深度大于虛 拟機所允許的深度,将抛出StackOverflowError異常;

如果虛拟機棧可以動态擴充(目前大部 分的Java虛拟機都可動态擴充,隻不過Java虛拟機規範中也允許固定長度的虛拟機棧),如 果擴充時無法申請到足夠的記憶體,就會抛出OutOfMemoryError異常

4.3 本地方法棧

與虛拟機棧一樣,本地方法 棧區域也會抛出StackOverflowError和OutOfMemoryError異常。
JVM記憶體區域劃分+垃圾機制

4.4 堆

Java堆是被所有線程共享的一塊記憶體區域,在虛拟機啟動時建立。此記憶體區域的唯一目的就 是存放對象執行個體,所有的對象執行個體以及數組都要在堆上配置設定。Java堆是垃圾收集器管理的主要區域,是以很多時候也被稱做“GC堆”

,但是随着JIT編譯器的發展與逃逸分析技 術逐漸成熟,棧上配置設定、标量替換[2]優化技術将會導緻一些微妙的變化發生,所有的對象都 配置設定在堆上也漸漸變得不是那麼“絕對”了。

Java堆可以處于實體上不連續的記憶體空間中,隻要邏輯上 是連續的即可,就像我們的磁盤空間一樣。在實作時,既可以實作成固定大小的,也可以是 可擴充的,不過目前主流的虛拟機都是按照可擴充來實作的==(通過-Xmx和-Xms控制)。如 果在堆中沒有記憶體完成執行個體配置設定,并且堆也無法再擴充時,将會抛出OutOfMemoryError異 常==。

堆記憶體細分為新生區,養老區,永久區(jdk1.6和jdk1.7方法區可以了解為永久區,JDK1.8之後已經将方法區取消,替代的是中繼資料區,jdk8真正開始廢棄永久代,而使用元空間(Metaspace),中繼資料區可以使用參數-XX:MaxMetaspaceSzie設定大小,這是一塊堆外的直接記憶體,與永久區不同,如果不指定大小,預設情況下,虛拟機會耗盡可用系統記憶體
JVM記憶體區域劃分+垃圾機制

4.5 方法區

JVM記憶體區域劃分+垃圾機制
方法區(Method Area)與Java堆一樣,是各個線程共享的記憶體區域,它用于存儲已被虛 拟機加載的類資訊、常量、靜态變量、即時編譯器編譯後的代碼等資料。雖然Java虛拟機規 範把方法區描述為堆的一個邏輯部分,但是它卻有一個别名叫做Non-Heap(非堆),目的是與Java堆區分開來。
相對而言,垃圾收集行為在這個 區域是比較少出現的,但并非資料進入了方法區就如永久代的名字一樣“永久”存在了。這區 域的記憶體回收目标主要是針對常量池的回收和對類型的解除安裝,一般來說,這個區域的回 收“成績”比較難以令人滿意,尤其是類型的解除安裝,條件相當苛刻,但是這部分區域的回收确 實是必要的。
當方法區無法滿足記憶體配置設定需求時,将抛出 OutOfMemoryError異常。

4.6 運作時常量池

運作時常量池(Runtime Constant Pool)是方法區的一部分。Class檔案中除了有類的版 本、字段、方法、接口等描述資訊外,還有一項資訊是常量池(Constant Pool Table),用于 存放編譯期生成的各種字面量和符号引用,這部分内容将在類加載後進入方法區的運作時常 量池中存放。
既然運作時常量池是方法區的一部分,自然受到方法區記憶體的限制,當常量池無法再申 請到記憶體時會抛出OutOfMemoryError異常。

5. 對象

JVM記憶體區域劃分+垃圾機制

6. OOM

除了程式計數器外,虛拟機記憶體的其他幾個運作時區域都 有發生OutOfMemoryError(稱OOM)異常的可能

6.1 虛拟機啟動參數設定

JVM記憶體區域劃分+垃圾機制

1.将堆的最小值-Xms參數與最 大值-Xmx參數設定為一樣即可避免堆自動擴充

2.通過參數-XX: +HeapDumpOnOutOfMemoryError可以讓虛拟機在出現記憶體溢出異常時Dump出目前的記憶體堆 轉儲快照以便事後進行分析

3 然-Xoss參數(設定本地方法棧大小)存在,但實際上是無效的,棧容量隻由-Xss參數設定

4.DirectMemory容量可通過-XX:MaxDirectMemorySize指定

6.2 Java堆溢出

Java堆用于存儲對象執行個體,隻要不斷地建立對象,并且保證GC Roots到對象之間有可達 路徑來避免垃圾回收機制清除這些對象,那麼在對象數量到達最大堆的容量限制後就會産生 記憶體溢出異常。
JVM記憶體區域劃分+垃圾機制

解決辦法:

要解決這個區域的異常,一般的手段是先通過記憶體映像分析工具,對Dump出來的堆轉儲快照進行分析,重點是确認記憶體中的對象是否是必要的,也 就是要先厘清楚到底是出現了記憶體洩漏(Memory Leak)還是記憶體溢出(Memory Overflow)
如果是記憶體洩露,可進一步通過工具檢視洩露對象到GC Roots的引用鍊。于是就能找到 洩露對象是通過怎樣的路徑與GC Roots相關聯并導緻垃圾收集器無法自動回收它們的。掌握 了洩露對象的類型資訊及GC Roots引用鍊的資訊,就可以比較準确地定位出洩露代碼的位 置。
如果不存在洩露,就是記憶體中的對象确實都還必須存活着,那就應當檢查虛 拟機的堆參數(-Xmx與-Xms),與機器實體記憶體對比看是否還可以調大,從代碼上檢查是 否存在某些對象生命周期過長、持有狀态時間過長的情況,嘗試減少程式運作期的記憶體消 耗。

6.3 虛拟機棧和本地方法棧溢出

關于虛拟機棧和本地方法棧,在Java虛拟機規範中描述了兩種異常:

如果線程請求的棧深度大于虛拟機所允許的最大深度,将抛出StackOverflowError異常。

如果虛拟機在擴充棧時無法申請到足夠的記憶體空間,則抛出OutOfMemoryError異常。

在單個線程下,無論是由于棧幀太大還是虛拟機棧容量太小,當記憶體無 法配置設定的時候,虛拟機抛出的都是StackOverflowError異常。
JVM記憶體區域劃分+垃圾機制
不斷地建立線程,可以産生記憶體溢出異常。。每個線程配置設定到的棧容量越大,可以 建立的線程數量自然就越少,建立線程時就越容易把剩下的記憶體耗盡。
出現StackOverflowError異常時有錯誤 堆棧可以閱讀,相對來說,比較容易找到問題的所在。
但是,如果是建立過多線程導緻的記憶體溢出,在不能減少線程數或者更換64位虛 拟機的情況下,就隻能通過減少最大堆和減少棧容量來換取更多的線程。

6.4 方法區和運作時常量池溢出

方法區溢出也是一種常見的記憶體溢出異常,一個類要被垃圾收集器回收掉,判定條件是 比較苛刻的。在經常動态生成大量Class的應用中,需要特别注意類的回收狀況。這類場景除 了上面提到的程式使用了CGLib位元組碼增強和動态語言之外,常見的還有:大量JSP或動态産 生JSP檔案的應用(JSP第一次運作時需要編譯為Java類)、基于OSGi的應用(即使是同一個 類檔案,被不同的加載器加載也會視為不同的類)等。

6.5本機直接記憶體溢出

由DirectMemory導緻的記憶體溢出,一個明顯的特征是在Heap Dump檔案中不會看見明顯 的異常,如果讀者發現OOM之後Dump檔案很小,而程式中又直接或間接使用了NIO,那就 可以考慮檢查一下是不是這方面的原因。

======================================

1.嘗試擴大堆記憶體,看結果,如果依然溢出,嘗試2

2.則分析記憶體,看那一塊出現問題

1.(使用專業工具)能夠看到代碼第幾行出錯,記憶體快照分析工具, MAT,JProfiler

2.Dubug 一行一行分析代碼

7. 垃圾收集與記憶體配置設定政策

為什麼要了解GC和記憶體配置設定呢?答案很簡單:當需 要排查各種記憶體溢出、記憶體洩漏問題時,當垃圾收內建為系統達到更高并發量的瓶頸時,就需要對這些“自動化”的技術實施必要的監控和調節。

從以下問題出發

  • 哪些記憶體需要回收?
  • 什麼時候回收?
  • 如何回收?

7.1 哪些記憶體需要回收?

垃圾回收主要是對 堆和方法區進行的

程式計數器、虛拟機棧、本地方法棧3個區域随線程而生,随 線程而滅;棧中的棧幀随着方法的進入和退出而有條不紊地執行着出棧和入棧操作。每一個棧幀中配置設定多少記憶體基本上是在類結構确定下來時就已知的(盡管在運作期會由JIT編譯器 進行一些優化,,先忽略,大體上可以認為是編譯期可知的),是以這幾個區域的記憶體配置設定和回收都具備确定性,在這幾個區域内就不需要過多考慮回收的問 題,因為方法結束或者線程結束時,記憶體自然就跟随着回收了。而Java堆和方法區則不一 樣,一個接口中的多個實作類需要的記憶體可能不一樣,一個方法中的多個分支需要的記憶體也 可能不一樣,我們隻有在程式處于運作期間時才能知道會建立哪些對象,這部分記憶體的配置設定 和回收都是動态的,垃圾收集器所關注的是這部分記憶體Java堆是GC回收的“重點區域”。堆中基本存放着所有對象執行個體,gc進行回收前,第一件事就是确認哪些對象存活,哪些死去[即不可能再被引用]

7.2 什麼時候回收?

當一個對象死了,不再被引用了,就可以對其進行回收了。

判斷對象是否存活算法

1.引用計數算法 給對象添加一個引用計數器,每當對象被引用一次就加1,引用失效時就減1。當為0的時候就判斷對象不會再被引用。

優點: 實作簡單效率高,被廣泛使用與如python何遊戲腳本語言上。

缺點: 難以解決循環引用的問題,就是假如兩個對象互相引用已經不會再被其它其它引用,導緻一直不會為0就無法進行回收。

== 2.可達性分析算法 == 目前主流的商用語言[如java、c#]采用的是可達性分析算法判斷對象是否存活。這個算法有效解決了循環利用的弊端。 它的基本思路是通過一個稱為“GC Roots”的對象為起始點,搜尋所經過的路徑稱為引用鍊,當一個對象到GC Roots沒有任何引用跟它連接配接,則證明對象是不可用的。
JVM記憶體區域劃分+垃圾機制

在Java語言中,可作為GC Roots的對象包括下面幾種:

  1. 虛拟機棧(棧幀中的本地變量表)中引用的對象。
  2. 方法區中類靜态屬性引用的對象。
  3. 方法區中常量引用的對象。
  4. 本地方法棧中JNI(即一般說的Native方法)

即使在可達性分析算法中不可達的對象,也并非是“非死不可”的,這時候它們暫時處 于“緩刑”階段,要真正宣告一個對象死亡,至少要經曆兩次标記過程:

JVM記憶體區域劃分+垃圾機制

它的運作代價高昂,不确定性大,無法保證各個對象的調用順序。不建議使用finalize()方法,

finalize()能做的所有工作,使用try-finally或者其他方式都可以做得更好、更及時。

7.3 如何回收?

7.3.1 GC

javaGC泛指java的垃圾回收機制,該機制是java與C/C++的主要差別之一,寫java代碼一般都不需要編寫記憶體回收或者垃圾清理的代碼,也不需要像C/C++那樣做類似delete/free的操作。記憶體會出現洩露,是以需要GC對記憶體進行回收,
GC分兩種:
  1. 新生代GC(Minor GC):指發生在新生代的垃圾收集動作,因為Java對象大多都具備朝 生夕滅的特性,是以Minor

    GC非常頻繁,一般回收速度也比較快。

  2. 老年代GC(Major GC/Full GC):指發生在老年代的GC,出現了Major GC,經常會伴 随至少一次的Minor

    GC(但非絕對的,在Parallel Scavenge收集器的收集政策裡就有直接進行 Major GC的政策選擇過程)。Major

    GC的速度一般會比Minor GC慢10倍以上。

7.3.2 記憶體配置設定與回收政策

配置設定的規則并不是百分之百固定的,其細節取決于目前使用的是哪一種垃圾收集器組合,還有虛拟 機中與記憶體相關的參數的設定。
JVM記憶體區域劃分+垃圾機制
  • 通過 NewRatio 控制新生代轉老年代的比例
  • 虛拟機提供了一個-XX:PretenureSizeThreshold參數,令大于這個設定值的對象直接在老

    年代配置設定。(PretenureSizeThreshold參數隻對Serial和ParNew兩款收集器有效,)

  • 通過MaxTenuringThreshold 設定對象進入老年代的年齡閥值
  • 虛拟機提供了-XX:+PrintGCDetails這個收集器日志參數,告訴虛拟機在發生垃圾收集

    行為時列印記憶體回收日志,并且在程序退出的時候輸出目前的記憶體各區域配置設定情況。

  • -Xms20M、-Xmx20M、-Xmn10M這3個參數限制了Java堆大小為20MB,不可擴 展,其中10MB配置設定給新生代,剩下的10MB配置設定給老年代。

7.3.3 垃圾收集算法

判斷對象是否存活算法 解決了哪些對象可以回收的問題,垃圾收集算法則關心怎麼回收。
  1. 标記/清除算法【最基礎】

    首先标記出所有需要回收的對象,在标記完成後統一回收所有 被标記的對象

缺點:

  1. 效率不高
  2. 空間問題,會産生大量空間碎片
JVM記憶體區域劃分+垃圾機制
  1. 複制算法

    它将可用記憶體按容 量劃分為大小相等的兩塊,每次隻使用其中的一塊。當這一塊的記憶體用完了,就将還存活着 的對象複制到另外一塊上面,然後再把已使用過的記憶體空間一次清理掉。這樣使得每次都是 對整個半區進行記憶體回收,記憶體配置設定時也就不用考慮記憶體碎片等複雜情況

缺點:空間代價大,記憶體使用率太低

JVM記憶體區域劃分+垃圾機制

現在的商業虛拟機都采用這種收集算法來回收新生代,IBM公司的專門研究表明,新生 代中的對象98%是“朝生夕死”的,是以并不需要按照1:1的比例來劃分記憶體空間,而是将記憶體 分為一塊較大的Eden空間和兩塊較小的Survivor空間,每次使用Eden和其中一塊Survivor[1]。 當回收時,将Eden和Survivor中還存活着的對象一次性地複制到另外一塊Survivor空間上,最 後清理掉Eden和剛才用過的Survivor空間。HotSpot虛拟機預設Eden和Survivor的大小比例是 8:1,也就是每次新生代中可用記憶體空間為整個新生代容量的90%(80%+10%),隻有10% 的記憶體會被“浪費”。當然,98%的對象可回收隻是一般場景下的資料,我們沒有辦法保證每 次回收都隻有不多于10%的對象存活,當Survivor空間不夠用時,需要依賴其他記憶體(這裡 指老年代)進行配置設定擔保(Handle Promotion)

  1. 标記/整理算法
JVM記憶體區域劃分+垃圾機制

總結:

記憶體效率: 複制>标記清除>标記壓縮

記憶體整齊度: 複制=标記壓縮>标記清除

記憶體使用率: 标記壓縮=标記清除>複制

7.3.4 java 虛拟機的分代收集算法

java jvm采用

分代收集算法

,對不同區域采用不同的回收算法:在新生代中,每次垃圾收集時都發現有大批對象死去,隻有少量存活,那就選用複制算法,隻需要付出少量存活對象的複制成本就可以完成收集。而老年代中因為對象存活率高、沒有額外空間對它進行配置設定擔保,就必須使用“标記—清理”或者“标記—整理”算法來進行回收。

新生代采用複制算法

絕大多數最新被建立的對象都會被配置設定到這裡,由于大部分在建立後很快變得不可達,很多對象被建立在新生代,然後“消失”。對象從這個區域“消失”的過程我們稱之為:Minor GC 。使用複制算法【複制算法比較适合用于存活率低的記憶體區域】。它優化了标記/清除算法的效率和記憶體碎片問題,将記憶體分為一塊Eden空間和From Survivor、To Survivor【保留白間】,三者預設比例為8:1:1,優先使用Eden區,若Eden區滿,則将對象複制到第二塊記憶體區上。但是不能保證每次回收都隻有不多于10%的對象存貨,是以Survivor區不夠的話,則會依賴老年代年存進行配置設定】。

GC開始時,對象隻會存于Eden和From Survivor區域,To Survivor【保留白間】為空。

GC進行時,Eden區所有存活的對象都被複制到To Survivor區,而From

Survivor區中,仍存活的對象會根據它們的年齡值決定去向,年齡值達到年齡門檻值(預設15是因為對象頭中年齡戰4bit,新生代每熬過一次垃圾回收,年齡+1),則移到老年代,沒有達到則複制到To

Survivor。

老年代采用标記/清除算法或标記/整理算法

對象沒有變得不可達,并且從新生代周期中存活了下來,會被拷貝到這裡。其區域配置設定的空間要比新生代多。也正由于其相對大的空間,發生在老年代的GC次數要比新生代少得多。對象從老年代中消失的過程,稱之為:Major GC 或者 Full GC。

由于老年代存活率高,沒有額外空間給他做擔保,必須使用這兩種算法。

7.3.5 垃圾收集器

記憶體回收如何進行是由虛拟機所采用的GC收集 器決定的,而通常虛拟機中往往不止有一種GC收集器。

JVM記憶體區域劃分+垃圾機制

垃圾收集器總結

  1. serial: 單線程 适合Client模式下的虛拟機 新生代:複制算法 老年代:标記整理算法
  2. serial old : 單線程 适合Client模式下的虛拟機 新生代:複制算法 老年代:标記整理算法
  3. ParNew : 多線程版本的serial,适合servser模式下的虛拟機 新生代:複制算法 老年代:标記整理算法
  4. parallel scavenge: 并行的,複制算法 目标則是達到一個可控制的吞吐量
  5. parallel old: 并行 标記整理
  6. CMS: 并發 标記清除 目标:擷取最短回收停頓時間

    過程: 初始标記- 會stop the word,時間很短,僅僅對GC可達的對象做一下标記

    并發标記-時間長一些

    重新标記-調整并發标記過程變動的标記對象

    并發清除

  7. G1: 面向服務端應用的垃圾收集器,具有以下特點:
    1. 并發并行
    2. 分代收集
    3. 空間整合
    4. 可預測的停頓

      過程:初始标記

      并發标記

      最終标記

      篩選回收

Serial收集器(-XX:+UseSerialGC)

Serial收集器是單線程的,Serial收集器對于運作在Client模式下的虛拟機來說是一個很好的 選擇。
JVM記憶體區域劃分+垃圾機制

ParNew收集器(-XX:+UseParNewGC)

ParNew收集器其實就是Serial收集器的多線程版本,是許多運作在Server模式下的虛拟機中首選的新生代收集器
JVM記憶體區域劃分+垃圾機制

Parallel Scavenge收集器(-XX:+UseParallelGC)

Parallel Scavenge收集器的目标則是達到一個可控制的吞吐量(Throughput)。所謂吞吐量就是CPU用于運作使用者代碼的時間與CPU總

消耗時間的比值,即吞吐量=運作使用者代碼時間/(運作使用者代碼時間+垃圾收集時間)

SerialOld 收集器(-XX:+UseSerialOldGC)

ParallelOld 收集器(-XX:+UseParallelOldGC)

JVM記憶體區域劃分+垃圾機制

CMS 收集器(-XX:+UseConcMarkSweepGC)

是HotSpot虛 拟機中第一款真正意義上的并發(Concurrent)收集器,以擷取最短回收停頓時間為目标的收集器。CMS收集器是基于“标記—清除”算法實作 的,它的運作過程相對于前面幾種收集器來說更複雜一些,整個過程分為4個步驟,包括:
  1. 初始标記(CMS initial mark)
  2. 并發标記(CMS concurrent mark)
  3. 重新标記(CMS remark)
  4. 并發清除(CMS concurrent sweep)
JVM記憶體區域劃分+垃圾機制

G1 收集器

G1是一款面向服務端應用的垃圾收集器,具有以下特點:

  1. 并發并行
  2. 分代收集
  3. 空間整合
  4. 可預測的停頓
JVM記憶體區域劃分+垃圾機制

7.4 GC日志了解

JVM記憶體區域劃分+垃圾機制

7.5 垃圾收集器參數總結

JVM記憶體區域劃分+垃圾機制
JVM記憶體區域劃分+垃圾機制
JVM記憶體區域劃分+垃圾機制