摘要:堆內(nèi)存使用分析,垃圾收集器日志解讀重要的東東在中,對象實例都是在堆上創(chuàng)建。機制是由提供,用來清理需要清除的對象,回收堆內(nèi)存。在中,是由一個被稱為垃圾回收器的守護線程執(zhí)行的。
堆內(nèi)存使用分析,垃圾收集器 GC 日志解讀 重要的東東
在Java中,對象實例都是在堆上創(chuàng)建。一些類信息,常量,靜態(tài)變量等存儲在方法區(qū)。堆和方法區(qū)都是線程共享的。
GC機制是由JVM提供,用來清理需要清除的對象,回收堆內(nèi)存。
GC機制將Java程序員從內(nèi)存管理中解放了出來,可以更關(guān)注于業(yè)務(wù)邏輯。
在Java中,GC是由一個被稱為垃圾回收器的守護線程執(zhí)行的。
在從內(nèi)存回收一個對象之前會調(diào)用對象的finalize()方法。
作為一個Java開發(fā)者不能強制JVM執(zhí)行GC;GC的觸發(fā)由JVM依據(jù)堆內(nèi)存的大小來決定。
System.gc()和Runtime.gc()會向JVM發(fā)送執(zhí)行GC的請求,但是JVM不保證一定會執(zhí)行GC。
如果堆沒有內(nèi)存創(chuàng)建新的對象了,會拋出OutOfMemoryError。
什么樣的對象會被GC回收?在垃圾收集器進行回收前,第一件事就是確定這些對象哪些還存活,哪些已經(jīng)死去。
點擊 查看 我的另一篇文章 《深入理解Java虛擬機》(三)垃圾收集器與內(nèi)存分配策略
測試環(huán)境系統(tǒng)
Microsoft Windows [版本 10.0.14393]
JDK
java version "1.8.0_112" Java(TM) SE Runtime Environment (build 1.8.0_112-b15) Java HotSpot(TM) 64-Bit Server VM (build 25.112-b15, mixed mode)
測試工具
IntelliJ IDEA 2017.2示例代碼
這里我們來通過一個小程序進行一下堆內(nèi)存分析,代碼如下:
package net.penglei.test; public class HeapTest { private static final int _1M = 1024 * 1024; public static void main(String[] args) throws InterruptedException { byte[] byte1 = new byte[2 * _1M]; byte[] byte2 = new byte[2 * _1M]; byte[] byte3 = new byte[2 * _1M]; byte[] byte4 = new byte[2 * _1M]; byte[] byte5 = new byte[2 * _1M]; byte[] byte6 = new byte[5 * _1M]; byte[] byte7 = new byte[2 * _1M]; } }設(shè)置JVM 參數(shù)配置
-Xms20m -Xmx20m -Xmn10m -verbose:gc -XX:+PrintGCDetails #輸出詳細GC日志模式 -XX:+PrintTenuringDistribution #輸出每次minor GC后新的存活周期的閾值 -XX:+PrintGCTimeStamps #輸出gc的觸發(fā)時間
我的 IntelliJ IDEA 配置
查看程序進程,堆詳情查看 jps -l 看進程,通過 jmap -heap pid 查看堆的概要信息
$ jps -l 5636 net.penglei.test.HeapTest堆配置
$ jmap -heap 5636 Attaching to process ID 5636, please wait... Debugger attached successfully. Server compiler detected. JVM version is 25.112-b15 using thread-local object allocation. Parallel GC with 8 thread(s) Heap Configuration: MinHeapFreeRatio = 0 MaxHeapFreeRatio = 100 #GC后如果發(fā)現(xiàn)空閑堆內(nèi)存占到整個預(yù)估堆內(nèi)存的N%(百分比) MaxHeapSize = 20971520 (20.0MB) # 堆最大空閑 jvm參數(shù) -Xms20m NewSize = 10485760 (10.0MB) # 年輕代空間 jvm參數(shù) -Xmn10m MaxNewSize = 10485760 (10.0MB) # 年輕代最大空間 OldSize = 10485760 (10.0MB) # 老年代空間 =(等于)堆內(nèi)存大小 -(減去)年輕代大小 NewRatio = 2 SurvivorRatio = 8 # 年輕代內(nèi)存又被分成三部分 Eden 空間 80% 而From Survivor 空間 和 To Survivor空間 分別占用10% MetaspaceSize = 21807104 (20.796875MB) # 設(shè)置元空間的最大值 jvm參數(shù) -XX:MaxMetaspaceSize CompressedClassSpaceSize = 1073741824 (1024.0MB) # 類指針壓縮空間大小, 默認為1G MaxMetaspaceSize = 17592186044415 MB # 是分配給類元數(shù)據(jù)空間的最大值 G1HeapRegionSize = 0 (0.0MB) # G1區(qū)塊的大小, 取值為1M至32M. 其取值是要根據(jù)最小Heap大小劃分出2048個區(qū)塊 ...執(zhí)行完 byte3
byte[] byte3 = new byte[2 * _1M];
$ jmap -heap 5636 ... Heap Usage: PS Young Generation Eden Space: capacity = 8388608 (8.0MB) used = 7635080 (7.281379699707031MB) free = 753528 (0.7186203002929688MB) 91.01724624633789% used From Space: capacity = 1048576 (1.0MB) used = 0 (0.0MB) free = 1048576 (1.0MB) 0.0% used To Space: capacity = 1048576 (1.0MB) used = 0 (0.0MB) free = 1048576 (1.0MB) 0.0% used PS Old Generation capacity = 10485760 (10.0MB) used = 0 (0.0MB) free = 10485760 (10.0MB) 0.0% used 1628 interned Strings occupying 148560 bytes.
數(shù)據(jù)區(qū)塊 | 堆總?cè)萘?/th> | 使用容量 | 剩余容量 | 使用占比 |
---|---|---|---|---|
年輕代 | 8.0MB | 7.28MB | 0.71MB | 91.0% |
幸存者0 | 1.0MB | 0.00MB | 1.0MB | 0.0% |
幸存者1 | 1.0MB | 0.00MB | 1.0MB | 0.0% |
老年代 | 10.0MB | 0.00MB | 10.MB | 0.0% |
PS Young Generation 年輕代空間,使用量達到 91.0%,內(nèi)存剩余0.71MB,當下次執(zhí)行byte4(占用年輕代2M內(nèi)存),會觸發(fā)Eden Space 空間(年輕代) Minor GC (年輕代垃圾收集)。
PS Old Generation 老年代空間,使用量達到 0.00%,內(nèi)存剩余10.MB,當下次執(zhí)行 byte4(占用年輕代2M內(nèi)存),上面 Eden Space 空間(年輕代) Minor GC (年輕代垃圾收集),會老年代占用一部分內(nèi)存。
執(zhí)行完 byte4byte[] byte4 = new byte[2 * _1M]控制臺打印的GC日志
641.638: [GC (Allocation Failure) Desired survivor size 1048576 bytes, new threshold 7 (max 15) [PSYoungGen: 7456K->728K(9216K)] 7456K->6880K(19456K), 0.0036244 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 641.642: [Full GC (Ergonomics) [PSYoungGen: 728K->0K(9216K)] [ParOldGen: 6152K->6700K(10240K)] 6880K->6700K(19456K), [Metaspace: 2848K->2848K(1056768K)], 0.0068164 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]GC日志分塊圖解 ps(畫的不好)
$ jmap -heap 5636 ... Heap Usage: PS Young Generation Eden Space: capacity = 8388608 (8.0MB) used = 2097168 (2.0000152587890625MB) free = 6291440 (5.9999847412109375MB) 25.00019073486328% used From Space: capacity = 1048576 (1.0MB) used = 0 (0.0MB) free = 1048576 (1.0MB) 0.0% used To Space: capacity = 1048576 (1.0MB) used = 0 (0.0MB) free = 1048576 (1.0MB) 0.0% used PS Old Generation capacity = 10485760 (10.0MB) used = 6861768 (6.543891906738281MB) free = 3623992 (3.4561080932617188MB) 65.43891906738281% used 1556 interned Strings occupying 143760 bytes.GC日志詳細分析
641.638: [GC (Allocation Failure) Desired survivor size 1048576 bytes, new threshold 7 (max 15) [PSYoungGen: 7456K->728K(9216K)] 7456K->6880K(19456K), 0.0036244 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
Parallel Scavenge 是年輕代 GC 收集器
641.638: [GC (Allocation Failure)
1641.638:是本次GC發(fā)生的時間,從jvm啟動起開始計時,單位為秒。這是一次Minor GC(年輕代垃圾收集),Minor GC 非常頻繁,回收速度快。
Desired survivor size 1048576 bytes, new threshold 7 (max 15)
期望的幸存者大小1048576字節(jié),新的存活周期的閾值為7(max 15)。
[PSYoungGen: 7456K->728K(9216K)]
格式為:[PSYoungGen: a->b(c)]
年輕代使用的是多線程垃圾收集器 Parallel Scavenge(新生代收集器,一般采用復(fù)制算法,并行的多線程收集器)
PSYoungGen,表示 GC發(fā)生在年輕代。
a 為GC前年輕代已占用空間,年輕代又細分為一個Eden 空間和From Survivor 空間 和 To Survivor空間。
b 為 Minor GC之后Eden空間GC后年輕代已占用空間 或者Survivor中已被占用的空間。
c 括號里的c表示整個年輕代的大小。
7456K->6880K(19456K)
格式為:x->y(z)
x 表示GC前堆的已占用空間,
y 表示GC后堆已占用空間,
z 表示堆的總大小。
, 0.0036244 secs]
表示本次GC所消耗的時間。
[Times: user=0.00 sys=0.00, real=0.00 secs]
提供cpu使用及時間消耗,user是用戶態(tài)消耗的cpu時間,sys是系統(tǒng)態(tài)消耗的cpu時間,real是實際的消耗時間。
老年代占用內(nèi)存空間 計算方式
老年代的內(nèi)存大小 = (等于) 堆內(nèi)存總大小 - (減去)年輕代內(nèi)存大小。
此例中就是19456K - 9216K = 10240K
Parallel Old 是Parallel Scavenge 收集器的老年代版本
641.642: [Full GC (Ergonomics) [PSYoungGen: 728K->0K(9216K)] [ParOldGen: 6152K->6700K(10240K)] 6880K->6700K(19456K), [Metaspace: 2848K->2848K(1056768K)], 0.0068164 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
641.642: [Full GC (Ergonomics)
老年代GC 又稱為Major GC,經(jīng)常會伴隨一次Minor GC(年輕代垃圾回收)速度比較慢
641.642:是本次GC發(fā)生的時間,從jvm啟動起開始計時,單位為秒。[Full GC (Ergonomics) ,表示執(zhí)行全局垃圾回收
[PSYoungGen: 728K->0K(9216K)]
格式為:[PSYoungGen: a->b(c)]
年輕代使用的是多線程垃圾收集器 Parallel Scavenge(新生代收集器,一般采用復(fù)制算法,并行的多線程收集器)
PSYoungGen,表示 GC發(fā)生在年輕代。
a 為GC前年輕代已占用空間,年輕代又細分為一個Eden 空間和From Survivor 空間 和 To Survivor空間。
b 為 Minor GC之后Eden空間GC后年輕代已占用空間 或者Survivor中已被占用的空間。
c 括號里的c表示整個年輕代的大小。
[ParOldGen: 6152K->6700K(10240K)]
格式為:[ParOldGen: x->y(z)]
老年代GC,使用 Parallel Old收集器,是Parallel Scavenge收集器的老年代版本,一搬采用多線程和“標記-整理”算法
ParOldGen 表示 GC 發(fā)生在老年代。
x 為GC前老年代已占用空間
y 為GC后老年代已占用空間
括號里的 z 為整個老年代的大小
6880K->6700K(19456K)
格式為:e->f(g)]
e 為GC前堆堆內(nèi)存占用,
f 為GC后堆堆內(nèi)存占用,
括號里的 g 為JVM整個堆的總大小。
[Metaspace: 2848K->2848K(1056768K)]
java8 特性是 把永久代 (Permanent Generation (PermGen)) 移植到元空間(Metaspace)
格式為:t->y(u)]
JDK8 HotSpot JVM 使用本地內(nèi)存來存儲類元數(shù)據(jù)信息并稱之為:元空間(Metaspace);這與Oracle JRockit 和IBM JVM’很相似。這將是一個好消息:意味著不會再有java.lang.OutOfMemoryError: PermGen問題默認情況下,類元數(shù)據(jù)只受可用的本地內(nèi)存限制(容量取決于是32位或是64位操作系統(tǒng)的可用虛擬內(nèi)存大小)
t 為元空間的垃圾回收前內(nèi)存占用
y 為元空間的垃圾回收后內(nèi)存占用
括號里的 u 為JVM元空間內(nèi)存總大小
, 0.0068164 secs]
表示本次GC所消耗的時間。
[Times: user=0.00 sys=0.00, real=0.01 secs]
提供cpu使用及時間消耗
user :用是用戶態(tài)消耗的cpu時間
sys :是系統(tǒng)態(tài)消耗的cpu時間
real :本次GC是實際的消耗時間
數(shù)據(jù)區(qū)塊 | 堆總?cè)萘?/th> | 使用容量 | 剩余容量 | 使用占比 |
---|---|---|---|---|
年輕代 | 8.0MB | 2.00MB | 5.99MB | 25.0% |
幸存者0 | 1.0MB | 0.00MB | 1.00MB | 0.0% |
幸存者1 | 1.0MB | 0.00MB | 1.00MB | 0.0% |
老年代 | 10.0MB | 6.54MB | 3.45MB | 65.4% |
年輕代 Eden Space 空間,使用量達到 25.0%,內(nèi)存剩余5.99MB,當下次執(zhí)行byte5(占用年輕代2M內(nèi)存) 不會觸發(fā)年輕代 Eden Space 空間 Minor GC(年輕代垃圾收集)。
老年代空間,使用量達到 6.54%,內(nèi)存剩余3.45MB,當下次執(zhí)行byte5(占用年輕代2M內(nèi)存),不會觸發(fā)老年代空間 Major GC(老年代垃圾收集),因為年輕代空間還夠用。
執(zhí)行完 byte5byte[] byte5 = new byte[2 * _1M];
$ jmap -heap 5636 ... Heap Usage: PS Young Generation Eden Space: capacity = 8388608 (8.0MB) used = 4356568 (4.154747009277344MB) free = 4032040 (3.8452529907226562MB) 51.9343376159668% used From Space: capacity = 1048576 (1.0MB) used = 0 (0.0MB) free = 1048576 (1.0MB) 0.0% used To Space: capacity = 1048576 (1.0MB) used = 0 (0.0MB) free = 1048576 (1.0MB) 0.0% used PS Old Generation capacity = 10485760 (10.0MB) used = 6861768 (6.543891906738281MB) free = 3623992 (3.4561080932617188MB) 65.43891906738281% used 1556 interned Strings occupying 143760 bytes.
數(shù)據(jù)區(qū)塊 | 堆總?cè)萘?/th> | 使用容量 | 剩余容量 | 使用占比 |
---|---|---|---|---|
年輕代 | 8.0MB | 4.15MB | 3.84MB | 51.9% |
幸存者0 | 1.0MB | 0.00MB | 1.00MB | 0.0% |
幸存者1 | 1.0MB | 0.00MB | 1.00MB | 0.0% |
老年代 | 10.0MB | 6.54MB | 3.45MB | 65.4% |
年輕代 Eden Space 空間,使用量達到 51.9%,內(nèi)存剩余3.84MB,當下次執(zhí)行byte6(占用年輕代5M內(nèi)存),導(dǎo)致年輕代空間不夠用了, 會觸發(fā)年輕代 Eden Space 空間 Minor GC(年輕代垃圾收集),把一部分內(nèi)存轉(zhuǎn)移到 PS Old Generation 老年代。
老年代 PS Old Generation 空間,使用量達到 6.54%,內(nèi)存剩余3.45MB,當下次執(zhí)行byte6(占用年輕代5M內(nèi)存),由于年輕代的一部分內(nèi)存,轉(zhuǎn)移到了老年代,導(dǎo)致老年代空間不夠用了,會觸發(fā)老年代 PS Old Generation 空間 Major GC(老年代垃圾收集)。
執(zhí)行完 byte6byte[] byte6 = new byte[5 * _1M];控制臺打印的GC日志
10342.704: [ Full GC (Ergonomics) [PSYoungGen: 4254K->2048K(9216K)] [ParOldGen: 6700K->8745K(10240K)] 10955K->10793K(19456K), [Metaspace: 2848K->2848K(1056768K)], 0.0154383 secs ] [Times: user=0.00 sys=0.03, real=0.02 secs]
這個GC 日志詳細解讀請參考,上面解讀,執(zhí)行完 byte4 的日志 ps(那個解讀更詳細)
這個是日志其實說的就是 :年輕代G回收前后,老年代GC回收前后,整個堆的GC回收前后,原數(shù)據(jù)空間回收前后,的內(nèi)存使用情況。三個內(nèi)存區(qū)塊GC回收所消耗的時間,提供cpu使用及時間消耗時間
簡單解讀GC日志PS Young Generation 年輕代 Eden Space 空間,使用量達到 4254K,當執(zhí)行byte6(占用年輕代5M內(nèi)存),導(dǎo)致年輕代空間不夠用了,會先觸發(fā)年輕代 Eden Space 空間 Minor GC(年輕代垃圾收集),把一部分內(nèi)存轉(zhuǎn)移到 PS Old Generation 老年代,GC回收后 Eden Space 空間 剩余 2048K。
PS Old Generation 老年代空間,使用量達到 6700K,當執(zhí)行byte6(占用年輕代5M內(nèi)存),由于年輕代的一部分內(nèi)存,轉(zhuǎn)移到了老年代,導(dǎo)致老年代空間不夠用了,會先觸發(fā)老年代 PS Old Generation 空間 Major GC(老年代垃圾收集)。GC回收后 Eden Space 空間 剩余 8745K。
$ jmap -heap 5636 ... Heap Usage: PS Young Generation Eden Space: capacity = 8388608 (8.0MB) used = 7507856 (7.1600494384765625MB) free = 880752 (0.8399505615234375MB) 89.50061798095703% used From Space: capacity = 1048576 (1.0MB) used = 0 (0.0MB) free = 1048576 (1.0MB) 0.0% used To Space: capacity = 1048576 (1.0MB) used = 0 (0.0MB) free = 1048576 (1.0MB) 0.0% used PS Old Generation capacity = 10485760 (10.0MB) used = 8955872 (8.540985107421875MB) free = 1529888 (1.459014892578125MB) 85.40985107421875% used 1556 interned Strings occupying 143760 bytes.
數(shù)據(jù)區(qū)塊 | 堆總?cè)萘?/th> | 使用容量 | 剩余容量 | 使用占比 |
---|---|---|---|---|
年輕代 | 8.0MB | 7.16MB | 0.83MB | 89.5% |
幸存者0 | 1.0MB | 0.00MB | 1.00MB | 0.0% |
幸存者1 | 1.0MB | 0.00MB | 1.00MB | 0.0% |
老年代 | 10.0MB | 8.54MB | 1.45MB | 85.4% |
byte[] byte7 = new byte[2 * _1M];簡單總結(jié)
參考 byte6 執(zhí)行后,PS Young Generation 年輕代 Eden Space 空間,使用量達到 89.5%,內(nèi)存剩余0.83MB,執(zhí)行byte7(占用年輕代2M內(nèi)存),導(dǎo)致年輕代空間不夠用了,會觸發(fā)Eden Space 空間(年輕代) Minor GC (年輕代垃圾收集)
參考 byte6 執(zhí)行后,PS Old Generation 老年代空間,使用量達到 85.4%,內(nèi)存剩余1.45MB,執(zhí)行byte7(占用年輕代2M內(nèi)存),會導(dǎo)致年輕代的GC回收放到老年代,而老年代也承擔不了,會 OutOfMemoryError。
控制臺打印的GC日志10427.298: [Full GC (Ergonomics) [PSYoungGen: 7331K->7168K(9216K)] [ParOldGen: 8745K->8745K(10240K)] 16077K->15913K(19456K), [Metaspace: 2849K->2849K(1056768K)], 0.0065366 secs] [Times: user=0.09 sys=0.02, real=0.01 secs] 10427.305: [Full GC (Allocation Failure) [PSYoungGen: 7168K->7168K(9216K)] [ParOldGen: 8745K->8745K(10240K)] 15913K->15913K(19456K), [Metaspace: 2849K->2849K(1056768K)], 0.0027873 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] Exception in thread "main" java.lang.OutOfMemoryError: Java heap space Heap at net.penglei.test.HeapTest.main(HeapTest.java:16) PSYoungGen total 9216K, used 7462K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000) eden space 8192K, 91% used [0x00000000ff600000,0x00000000ffd49b60,0x00000000ffe00000) from space 1024K, 0% used [0x00000000ffe00000,0x00000000ffe00000,0x00000000fff00000) to space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000) ParOldGen total 10240K, used 8745K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000) object space 10240K, 85% used [0x00000000fec00000,0x00000000ff48a708,0x00000000ff600000) Metaspace used 2880K, capacity 4486K, committed 4864K, reserved 1056768K class space used 309K, capacity 386K, committed 512K, reserved 1048576K Disconnected from the target VM, address: "127.0.0.1:59679", transport: "socket" Process finished with exit code 1 。
[Full GC (Ergonomics) [PSYoungGen: 7331K->7168K(9216K)]
本次 Minor GC 發(fā)生在PS Young Generation 年輕代 Eden Space 空間,由于老年代已經(jīng)占用85.4%,老年代空間不夠用,本次年輕代垃圾回收沒什么太大作用,只回收了一丟丟。
[ParOldGen: 8745K->8745K(10240K)]
本次 Major GC 發(fā)生在 PS Old Generation 老年代 ,由于老年代已經(jīng)占用85.4% , 空間不夠回收用,導(dǎo)致老年代回收沒有效果**
16077K->15913K(19456K)
這些是告訴你,Exception 前 內(nèi)存溢出前的堆占用情況
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space Heap at net.penglei.test.HeapTest.main(HeapTest.java:16) PSYoungGen total 9216K, used 7462K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000) eden space 8192K, 91% used [0x00000000ff600000,0x00000000ffd49b60,0x00000000ffe00000) from space 1024K, 0% used [0x00000000ffe00000,0x00000000ffe00000,0x00000000fff00000) to space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000) ParOldGen total 10240K, used 8745K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000) object space 10240K, 85% used [0x00000000fec00000,0x00000000ff48a708,0x00000000ff600000) Metaspace used 2880K, capacity 4486K, committed 4864K, reserved 1056768K class space used 309K, capacity 386K, committed 512K, reserved 1048576K
此刻的 PS Young Generation 年輕代JVM 堆回收前占用16077K,年輕代JVM 堆回收后占用16077K ,JVM 堆總大小 19456K
[Full GC (Allocation Failure) [PSYoungGen: 7168K->7168K(9216K)] [ParOldGen: 8745K->8745K(10240K)] 15913K->15913K(19456K)
PSYoungGen 年輕代 Minor GC , ParOldGen 老年代 Major GC 老年代承擔不了 15913K 內(nèi)存,然后就 OutOfMemoryError 堆內(nèi)存溢出了
為什了 老年代這次要 承擔15913K 內(nèi)存呢?因為前兩次 Full GC 都沒有成功,導(dǎo)致內(nèi)存積壓了一些在堆空間,堆空間自然放不下,然后要放到老年代,老年代放不下就堆內(nèi)存溢出了
總結(jié) 內(nèi)存分配與回收策略對象優(yōu)先在新生代分配
大對象直接進入老年代
長期存活的對象將進入老年代
動態(tài)對象年齡判斷:如果在Survivor空間中相同年齡所有對象大小總和大于Survivor空間的一半,大于或等于該年齡的對象直接進入老年代。
空間分配擔保:發(fā)生Minor GC前,虛擬機會先檢查老年代最大可用連續(xù)空間是否大于新生代所有對象總空間,如果不成立,虛擬機會查看HandlePromotionFailure設(shè)置值是否允許擔保失敗,如果允許繼續(xù)檢查老年代最大可用的連續(xù)空間是否大于歷次晉升到老年代的平均大小,如果大于會嘗試進行一次Minor GC;如果小于或者不允許冒險,會進行一次Full GC。
1 對象優(yōu)先在eden分配大多數(shù)情況下,對象優(yōu)先在新生代的Eden區(qū)分配。
當Eden區(qū)沒有足夠的空間時,虛擬機將發(fā)起一次Minor GC。
Minor GC與Full GC。
Minor GC:新生代GC,非常頻繁,回收速度快。
Fulll GC:老年代GC,又稱為Major GC,經(jīng)常會伴隨一次Minor GC,速度比較慢。
2 大對象直接進入老年代大對象是指需要大量連續(xù)的內(nèi)存空間的Java對象,最典型的大對象就是那種很長的字符串以及數(shù)組。
虛擬機提供了一個參數(shù):PretenureSizeThreshold,大于這個參數(shù)的對象將直接在老年代分配。
3 長期存活的對象將進入老年代虛擬機給每個對象定義了一個對象年齡計數(shù)器(Age),對象每經(jīng)過一次Minor GC后仍然存活,且能被Survivor容納的話,年齡就 +1 ,當年齡增加到一定程度(默認為15),就會被晉升到老年代中,這個閾值可以通過參數(shù) MaxTenuringThreshold 來設(shè)置。
4.動態(tài)對象年齡的判定
4 動態(tài)對象年齡判定如果在Survivor空間中相同年齡所有對象大小的總和大于Survivor空間的一半,年齡大于或等于該年齡的對象就可以直接進入老年代。
5 空間分配擔保為了更好的適應(yīng)不同程序的內(nèi)存狀況,對象年齡不是必須到達閾值才會進入老年代。
只要老年代的連續(xù)空間大于新生代對象總大小或者歷次晉升的平均大小就會進行Minor GC,否則將進行Full GC。
《深入理解Java虛擬機:JVM高級特性與最佳實踐_周志明.高清掃描版.pdf》
下載地址:鏈接:http://pan.baidu.com/s/1miBQCBY 密碼:9kbn
推薦閱讀《深入理解Java虛擬機》(一)Java虛擬機發(fā)展史
《深入理解Java虛擬機》(二)Java虛擬機運行時數(shù)據(jù)區(qū)
《深入理解Java虛擬機》(三)垃圾收集器與內(nèi)存分配策略
《深入理解Java虛擬機》(四)虛擬機性能監(jiān)控與故障處理工具
《深入理解Java虛擬機》(五)JVM調(diào)優(yōu) - 工具
《深入理解Java虛擬機》(六)堆內(nèi)存使用分析,GC 日志解讀
Contact作者:鵬磊
出處:http://www.ymq.io
Email:admin@souyunku.com
版權(quán)歸作者所有,轉(zhuǎn)載請注明出處
Wechat:關(guān)注公眾號,搜云庫,專注于開發(fā)技術(shù)的研究與知識分享
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/67590.html
摘要:當兩個對象相互引用時,這兩個對象就不會被回收引用計數(shù)算法不被主流虛擬機采用,主要原因是它很難解決對象之間相互循環(huán)引用的問題。 垃圾收集器與內(nèi)存分配策略 詳解 3.1 概述 本文參考的是周志明的 《深入理解Java虛擬機》第三章 ,為了整理思路,簡單記錄一下,方便后期查閱。 3.2 對象已死嗎 在垃圾收集器進行回收前,第一件事就是確定這些對象哪些還存活,哪些已經(jīng)死去。 3.2.1 引用...
摘要:虛擬機性能監(jiān)控與故障處理工具詳解概述本文參考的是周志明的深入理解虛擬機第四章,為了整理思路,簡單記錄一下,方便后期查閱。虛擬機堆轉(zhuǎn)儲快照分析工具功能用于分析生成的。 虛擬機性能監(jiān)控與故障處理工具 詳解 4.1 概述 本文參考的是周志明的 《深入理解Java虛擬機》 第四章 ,為了整理思路,簡單記錄一下,方便后期查閱。 JDK本身提供了很多方便的JVM性能調(diào)優(yōu)監(jiān)控工具,除了集成式的Vis...
摘要:虛擬機發(fā)展史注本文大部分摘自深入理解虛擬機第二版作為一名開發(fā)人員,不能局限于語言規(guī)范,更需要對虛擬機規(guī)范有所了解。虛擬機規(guī)范有多種實現(xiàn),其中是和中所帶的虛擬機,也是目前使用范圍最廣的虛擬機。世界第一款商用虛擬機。號稱世界上最快的虛擬機。 Java虛擬機發(fā)展史 注:本文大部分摘自《深入理解Java虛擬機(第二版)》 作為一名Java開發(fā)人員,不能局限于Java語言規(guī)范,更需要對Java虛...
摘要:看來還是功力不夠,索性拆成了六篇文章,分別從自動內(nèi)存管理機制類文件結(jié)構(gòu)類加載機制字節(jié)碼執(zhí)行引擎程序編譯與代碼優(yōu)化高效并發(fā)六個方面來做更加細致的介紹。本文先說說虛擬機的自動內(nèi)存管理機制。在類加載檢查通過后,虛擬機將為新生對象分配內(nèi)存。 歡迎關(guān)注微信公眾號:BaronTalk,獲取更多精彩好文! 書籍真的是常讀常新,古人說「書讀百遍其義自見」還是蠻有道理的。周志明老師的這本《深入理解 Ja...
摘要:虛擬機運行時數(shù)據(jù)區(qū)分為以下幾個部分。程序計數(shù)器也是在虛擬機規(guī)范中唯一沒有規(guī)定任何異常情況的區(qū)域。在方法運行期間不會改變局部變量表的大小。長度在位和位的虛擬機中,分別為官方稱它為。 Java虛擬機運行時數(shù)據(jù)區(qū) 詳解 2.1 概述 本文參考的是周志明的 《深入理解Java虛擬機》第二章 ,為了整理思路,簡單記錄一下,方便后期查閱。 2.2 運行時數(shù)據(jù)區(qū)域 Java虛擬機在Java程序運行時...
閱讀 898·2019-08-30 15:54
閱讀 1466·2019-08-30 15:54
閱讀 2400·2019-08-29 16:25
閱讀 1292·2019-08-29 15:24
閱讀 749·2019-08-29 12:11
閱讀 2506·2019-08-26 10:43
閱讀 1227·2019-08-26 10:40
閱讀 466·2019-08-23 16:24