点击 查看 我的另一篇文章 《深入理解Java虚拟机》(三)垃圾收集器与内存分配策略
这里我们来通过一个小程序进行一下堆内存分析,代码如下:
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];
}
}
-Xms20m
-Xmx20m
-Xmn10m
-verbose:gc
-XX:+PrintGCDetails #输出详细GC日志模式
-XX:+PrintTenuringDistribution #输出每次minor GC后新的存活周期的阈值
-XX:+PrintGCTimeStamps #输出gc的触发时间
我的 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后如果发现空闲堆内存占到整个预估堆内存的N%(百分比)
MaxHeapSize = 20971520 (20.0MB) # 堆最大空闲 jvm参数 -Xms20m
NewSize = 10485760 (10.0MB) # 年轻代空间 jvm参数 -Xmn10m
MaxNewSize = 10485760 (10.0MB) # 年轻代最大空间
OldSize = 10485760 (10.0MB) # 老年代空间 =(等于)堆内存大小 -(减去)年轻代大小
NewRatio = 2
SurvivorRatio = 8 # 年轻代内存又被分成三部分 Eden 空间 80% 而From Survivor 空间 和 To Survivor空间 分别占用10%
MetaspaceSize = 21807104 (20.796875MB) # 设置元空间的最大值 jvm参数 -XX:MaxMetaspaceSize
CompressedClassSpaceSize = 1073741824 (1024.0MB) # 类指针压缩空间大小, 默认为1G
MaxMetaspaceSize = 17592186044415 MB # 是分配给类元数据空间的最大值
G1HeapRegionSize = 0 (0.0MB) # G1区块的大小, 取值为1M至32M. 其取值是要根据最小Heap大小划分出2048个区块
...
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.
数据区块 | 堆总容量 | 使用容量 | 剩余容量 | 使用占比 |
---|---|---|---|---|
年轻代 | 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% |
byte[] byte4 = new byte[2 * _1M]
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]
$ 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.
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)
Minor GC
(年轻代垃圾收集),Minor GC 非常频繁,回收速度快。Desired survivor size 1048576 bytes, new threshold 7 (max 15)
[PSYoungGen: 7456K->728K(9216K)]
格式为:[PSYoungGen: a->b(c)]
年轻代使用的是多线程垃圾收集器
Parallel Scavenge
(新生代收集器,一般采用复制算法,并行的多线程收集器)
7456K->6880K(19456K)
格式为:x->y(z)
, 0.0036244 secs]
[Times: user=0.00 sys=0.00, real=0.00 secs]
老年代占用内存空间 计算方式
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,经常会伴随一次Minor GC(年轻代垃圾回收)速度比较慢
[PSYoungGen: 728K->0K(9216K)]
格式为:[PSYoungGen: a->b(c)]
年轻代使用的是多线程垃圾收集器
Parallel Scavenge
(新生代收集器,一般采用复制算法,并行的多线程收集器)
[ParOldGen: 6152K->6700K(10240K)]
格式为:[ParOldGen: x->y(z)]
老年代GC,使用 Parallel Old收集器,是Parallel Scavenge收集器的老年代版本,一搬采用多线程和“标记-整理”算法
6880K->6700K(19456K)
格式为:e->f(g)]
[Metaspace: 2848K->2848K(1056768K)]
java8 特性是 把永久代 (Permanent Generation (PermGen)) 移植到元空间(Metaspace)
格式为:t->y(u)]
JDK8 HotSpot JVM 使用本地内存来存储类元数据信息并称之为:元空间(Metaspace);这与Oracle JRockit 和IBM JVM’很相似。这将是一个好消息:意味着不会再有
java.lang.OutOfMemoryError: PermGen
问题默认情况下,类元数据只受可用的本地内存限制(容量取决于是32位或是64位操作系统的可用虚拟内存大小)
, 0.0068164 secs]
[Times: user=0.00 sys=0.00, real=0.01 secs]
提供cpu使用及时间消耗
数据区块 | 堆总容量 | 使用容量 | 剩余容量 | 使用占比 |
---|---|---|---|---|
年轻代 | 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% |
byte[] 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.
数据区块 | 堆总容量 | 使用容量 | 剩余容量 | 使用占比 |
---|---|---|---|---|
年轻代 | 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% |
byte[] byte6 = new byte[5 * _1M];
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 日志详细解读请参考,上面解读,执行完 byte4 的日志 ps(那个解读更详细)
$ 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.
数据区块 | 堆总容量 | 使用容量 | 剩余容量 | 使用占比 |
---|---|---|---|---|
年轻代 | 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];
OutOfMemoryError
。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)]
[ParOldGen: 8745K->8745K(10240K)]
16077K->15913K(19456K)
这些是告诉你,Exception 前 内存溢出前的堆占用情况
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
[Full GC (Allocation Failure)
[PSYoungGen: 7168K->7168K(9216K)] [ParOldGen: 8745K->8745K(10240K)] 15913K->15913K(19456K)
大多数情况下,对象优先在新生代的Eden区分配。 当Eden区没有足够的空间时,虚拟机将发起一次Minor GC。 Minor GC与Full GC。
PretenureSizeThreshold
,大于这个参数的对象将直接在老年代分配。
MaxTenuringThreshold
来设置。4.动态对象年龄的判定
《深入理解Java虚拟机:JVM高级特性与最佳实践_周志明.高清扫描版.pdf》
下载地址:链接:http://pan.baidu.com/s/1miBQCBY 密码:9kbn
《深入理解Java虚拟机》(四)虚拟机性能监控与故障处理工具
《深入理解Java虚拟机》(六)堆内存使用分析,GC 日志解读