我有一个简单的演示来检查JVM内存分配和释放的详细信息。
Java版本
$ java -version
java version "1.8.0_201"
Java(TM) SE Runtime Environment (build 1.8.0_201-b09)
Java HotSpot(TM) 64-Bit Server VM (build 25.201-b09, mixed mode)
演示
/**
* VM Options: -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8
*/
public class DefaultCollector {
private static final int _1MB = 1024 * 1024;
public static void main(String... args) {
byte[] arr1 = new byte[2 * _1MB];
byte[] arr2 = new byte[2 * _1MB];
byte[] arr3 = new byte[2 * _1MB];
byte[] arr4 = new byte[4 * _1MB];
}
}
GC日志
[GC (Allocation Failure) [PSYoungGen: 6516K->695K(9216K)] 6516K->4791K(19456K), 0.0019189 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
Heap
PSYoungGen total 9216K, used 7408K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
eden space 8192K, 81% used [0x00000000ff600000,0x00000000ffc8e6a8,0x00000000ffe00000)
from space 1024K, 67% used [0x00000000ffe00000,0x00000000ffeadcb0,0x00000000fff00000)
to space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)
ParOldGen total 10240K, used 4096K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
object space 10240K, 40% used [0x00000000fec00000,0x00000000ff000020,0x00000000ff600000)
Metaspace used 3273K, capacity 4556K, committed 4864K, reserved 1056768K
class space used 357K, capacity 392K, committed 512K, reserved 1048576K
Disconnected from the target VM, address: '127.0.0.1:38815', transport: 'socket'
-Xms20M -Xmx20M -Xmn10M -XX:SurvivorRatio=8
已经设置好,eden - 8M, from - 1M, and to - 1M
清楚地显示了,为什么用PSYoungGen total 9216K
而不是10240K
?Allocation Failure
仍然存在空间,因为 Tenured 并且-XX:+HandlePromotionFailure
应该默认为true
,因为JDK 6和更高版本已经存在? PSYoungGen: 6516K->695K(9216K)
仍然存在,因为三个数组在 Young Generation 中仍然存在?是因为分配失败吗?Metaspace
占用大量内存Metaspace used 3273K
?如果不只是键入信息,那里到底有什么?我还尝试了其他组合:
大小:1,1,1,4 =>伊甸园70%,使用年限40%
为什么?
大小:1、1、1、1 =>伊甸园80%(〜6M),使用期限为0%
为什么在伊甸园中80%(〜6M)而不是4M?
在@Stephen C的帮助下,我发现在 IntelliJ Terminal 中登录前的输出为
/usr/lib/jvm/java-8-oracle/bin/java -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:42103,suspend=y,server=n -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -javaagent:/home/hearen/Downloads/idea-IU-183.5429.30/lib/rt/debugger-agent.jar -Dfile.encoding=UTF-8 -classpath /usr/lib/jvm/java-8-oracle/jre/lib/charsets.jar:/usr/lib/jvm/java-8-oracle/jre/lib/deploy.jar:/usr/lib/jvm/java-8-oracle/jre/lib/ext/cldrdata.jar:/usr/lib/jvm/java-8-oracle/jre/lib/ext/dnsns.jar:/usr/lib/jvm/java-8-oracle/jre/lib/ext/jaccess.jar:/usr/lib/jvm/java-8-oracle/jre/lib/ext/jfxrt.jar:/usr/lib/jvm/java-8-oracle/jre/lib/ext/localedata.jar:/usr/lib/jvm/java-8-oracle/jre/lib/ext/nashorn.jar:/usr/lib/jvm/java-8-oracle/jre/lib/ext/sunec.jar:/usr/lib/jvm/java-8-oracle/jre/lib/ext/sunjce_provider.jar:/usr/lib/jvm/java-8-oracle/jre/lib/ext/sunpkcs11.jar:/usr/lib/jvm/java-8-oracle/jre/lib/ext/zipfs.jar:/usr/lib/jvm/java-8-oracle/jre/lib/javaws.jar:/usr/lib/jvm/java-8-oracle/jre/lib/jce.jar:/usr/lib/jvm/java-8-oracle/jre/lib/jfr.jar:/usr/lib/jvm/java-8-oracle/jre/lib/jfxswt.jar:/usr/lib/jvm/java-8-oracle/jre/lib/jsse.jar:/usr/lib/jvm/java-8-oracle/jre/lib/management-agent.jar:/usr/lib/jvm/java-8-oracle/jre/lib/plugin.jar:/usr/lib/jvm/java-8-oracle/jre/lib/resources.jar:/usr/lib/jvm/java-8-oracle/jre/lib/rt.jar:/home/hearen/git/personal/about-java/target/classes:/usr/lib/jvm/java-8-oracle/lib/dt.jar:/usr/lib/jvm/java-8-oracle/lib/tools.jar:/usr/lib/jvm/java-8-oracle/lib/sa-jdi.jar:/usr/lib/jvm/java-8-oracle/lib/jconsole.jar:/usr/lib/jvm/java-8-oracle/lib/packager.jar:/usr/lib/jvm/java-8-oracle/lib/javafx-mx.jar:/usr/lib/jvm/java-8-oracle/lib/ant-javafx.jar:/home/hearen/.m2/repository/org/projectlombok/lombok/1.16.20/lombok-1.16.20.jar:/home/hearen/.m2/repository/junit/junit/4.11/junit-4.11.jar:/home/hearen/.m2/repository/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar:/home/hearen/.m2/repository/cglib/cglib/3.2.4/cglib-3.2.4.jar:/home/hearen/.m2/repository/org/ow2/asm/asm/5.1/asm-5.1.jar:/home/hearen/.m2/repository/org/apache/ant/ant/1.9.6/ant-1.9.6.jar:/home/hearen/.m2/repository/org/apache/ant/ant-launcher/1.9.6/ant-launcher-1.9.6.jar:/home/hearen/Downloads/idea-IU-183.5429.30/lib/idea_rt.jar jvm.allocation.DefaultCollector
然后我手动使用CLI编译并运行程序,
$ javac DefaultCollector.java
$ java -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 DefaultCollector
输出将变为
Heap
PSYoungGen total 9216K, used 6815K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
eden space 8192K, 83% used [0x00000000ff600000,0x00000000ffca7ff8,0x00000000ffe00000)
from space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)
to space 1024K, 0% used [0x00000000ffe00000,0x00000000ffe00000,0x00000000fff00000)
ParOldGen total 10240K, used 4096K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
object space 10240K, 40% used [0x00000000fec00000,0x00000000ff000010,0x00000000ff600000)
Metaspace used 2464K, capacity 4486K, committed 4864K, reserved 1056768K
class space used 265K, capacity 386K, committed 512K, reserved 1048576K
显然,大数组 4M 直接放入 Tenured 中,而其他三个 2M 在 Young 中分配以上结果。
答案 0 :(得分:5)
我怀疑其中大部分可以通过JVM中的“其他内容”来解释。
输出的最后一行是您已(已)将代理附加到JVM的证据。
Disconnected from the target VM, address: '127.0.0.1:38815', transport: 'socket'
AFAIK,该代理将导致JVM加载,编译等应用程序未直接使用的类。然后,代理将为堆,缓冲区等分配堆对象以处理监视。
这将同时增加常规堆和元空间的使用。
我建议您在没有附加代理的情况下从shell /命令行重复此实验。通过命令行选项打开GC日志记录以获取GC统计信息。
您的更新。
显然,大型阵列4M直接进入终身制,而其他三个2M在Young中分配给我们以上结果。
正确。有一个阈值可以将对象直接分配到使用权空间中。可以调整....