查看 JVM 内存的占用情况
编写代码
package com.test;
public class PrintMemoryDemo {
public static void main(String[] args) {
// 堆内存总量
long totalMemory = Runtime.getRuntime().totalMemory();
// jvm 试图使用的最大堆内存
long maxMemory = Runtime.getRuntime().maxMemory();
// jvm 剩余的堆内存
long freeMemory = Runtime.getRuntime().freeMemory();
System.out.println("jvm 堆内存总量: " + totalMemory/1024/1024 + "MB");
System.out.println("jvm 最大内存: " + maxMemory/1024/1024 + "MB");
System.out.println("jvm 剩余内存: " + freeMemory/1024/1024 + "MB");
}
}
运行程序
$ java com.test.PrintMemoryDemo
jvm 堆内存总量: 366MB
jvm 最大内存: 5431MB
jvm 剩余内存: 362MB
本机的内存为 24G,初始化堆内内存为 366M,接近本机的 1/64(24G/64=384M)。最大堆内存为 5431M,接近本机的 1/4(24G/4=6144M)
Eden 区优先分配
首先我们需要了解下 JVM 的四种垃圾收集场景:
- Minor GC 和 Young GC 都是指新生代的垃圾收集。
- Major GC 和 Old GC 都是指老年代的垃圾收集。(CMS 收集器专属)
- Mixed GC 混合收集,指收集整个新生代以及部分老年代的垃圾收集。(G1 收集器专属)
- Full GC 整堆收集,指收集整个 Java 堆和方法区垃圾收集。
新生代和老年代在 Java 虚拟机内存体系 着重介绍了,我们在这里还是简单复习下。 堆分为新生代 + 老年代,新生代又被划分为 Eden
区和 Survivor
区,Survivor
又被划分为两个相等大小的 s0
和 s1
区。其中 Eden
区大小和 Survivor
区大小是 8:1。默认情况下新生代占堆的 1/3,老年代占堆的 2/3。 如下图所示,气泡中的数字代表占用内存的份数,比如 Eden 区占用:
大多数情况下,新创建的对象都会在新生代的 Eden 区中分配,当 Eden 区没有足够的空间分配时,虚拟机将会发生一次 Minor GC。 下面我们设置程序的堆大小为 30 MB,且不可扩大。
编写代码
package com.test;
public class EdenAllocationDemo {
// 定义占用 1MB 空间的变量
private static final int _1MB = 1024 * 1024;
public static void main(String[] args) {
byte[] allocation1, allocation2, allocation3, allocation4;
allocation1 = new byte[2 * _1MB];
allocation2 = new byte[2 * _1MB];
allocation3 = new byte[2 * _1MB];
allocation4 = new byte[4 * _1MB];
}
}
执行程序
$ java -Xms30m -Xmx30m -Xmn10m -XX:SurvivorRatio=8 -XX:+PrintGCDetails com.test.EdenAllocationDemo
Heap
PSYoungGen total 9216K, used 7456K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
eden space 8192K, 91% used [0x00000000ff600000,0x00000000ffd48008,0x00000000ffe00000)
from space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)
to space 1024K, 0% used [0x00000000ffe00000,0x00000000ffe00000,0x00000000fff00000)
ParOldGen total 20480K, used 4096K [0x00000000fe200000, 0x00000000ff600000, 0x00000000ff600000)
object space 20480K, 20% used [0x00000000fe200000,0x00000000fe600010,0x00000000ff600000)
Metaspace used 2678K, capacity 4486K, committed 4864K, reserved 1056768K
class space used 289K, capacity 386K, committed 512K, reserved 1048576K
命令行解释:
-Xms30M
最小堆内存 30 M。-Xmx30M
最大堆内存 30 M。-Xmn10M
新生代占用堆内存 10 M。-XX:SurvivorRatio=8
新生代中的 Eden 区和新生代中的一个 Survivor 区比例为 8:1。- 堆中的新生代占用 10 MB,占用堆内存的 1/3,剩下的 20 MB 分配给老年代。新生代中的一个 Survivor 区占用 1/10(1 MB),另外一个 Survivor 区占用 1/10(1 MB),Eden 区占用 8/10(8 MB)。
结果分析:
新生代总内存 9216K (Eden区 + 1个Suvivor区,已使用 7456K)
新生代Eden区 8192K(8M),使用 7456/8162=91%
from suvivor 区 1024 K,已使用 0%
to suvivor 区 1024 K,已使用 0%
老年代总内存 20480 K,已使用 4096 K,4096/20480=20%创建的 allocation1、allocation2、allocation3 分配到了 Eden 区,占用 6M,当分配 allocation4(需要4M) 时,因为新生代内总内存总共只有 9M(8M Eden 区 + 1M Suvivor 区) ,allocation4 不能放进 Eden 区,直接放到了老年代。