你无法控制你想控制的, -Xmx
只控制Java堆,不控制消耗本机记忆由 JVM 执行,根据实现的不同,其消耗方式完全不同。 VisualVM 仅向您显示堆正在消耗什么,它不会显示整个 JVM 正在消耗什么本机记忆作为操作系统进程。您必须使用操作系统级别的工具才能看到这一点,它们将报告完全不同的数字,通常比 VisualVM 报告的任何数字都要大得多,因为 JVM 耗尽了本机记忆以完全不同的方式。
来自下面的文章感谢您的内存(了解 JVM 如何在 Windows 和 Linux 上使用本机内存) https://web.archive.org/web/20210314194158/http://www.ibm.com/developerworks/java/library/j-nativememory-linux/
维护堆和垃圾收集器使用您无法控制的本机内存。
需要更多本机内存来维持状态
维护 Java 堆的内存管理系统。数据结构
必须分配以跟踪可用存储并记录进度
收集垃圾。这些数据结构的确切大小和性质
随实施情况的不同而变化,但许多都与规模成正比
堆。
JIT 编译器使用本机内存,就像javac
would
字节码编译使用本机内存(与静态
像 gcc 这样的编译器需要内存来运行),但是输入(
字节码)和 JIT 的输出(可执行代码)也必须
存储在本机内存中。 Java 应用程序包含许多
JIT 编译的方法比小型应用程序使用更多的本机内存。
然后你就有了使用本机内存的类加载器
Java 应用程序由定义对象结构的类组成
和方法逻辑。他们还使用 Java 运行时类中的类
库(例如 java.lang.String)并且可以使用第三方
图书馆。这些类需要在内存中存储尽可能长的时间
它们正在被使用。类的存储方式因实现而异。
我什至不会开始引用有关线程的部分,我想您已经明白了-Xmx
不控制你认为它控制的东西,它控制 JVM 堆,而不是一切
进入 JVM 堆,堆占用的本机内存比您指定的要多得多
管理和簿记。
简单明了,JVM 使用的内存比提供的内存多-Xms and -Xmx以及其他命令行参数。 https://stackoverflow.com/a/9146775/177800
这里有一个关于 JVM 如何分配和管理内存的非常详细的文章 https://web.archive.org/web/20210314194158/http://www.ibm.com/developerworks/java/library/j-nativememory-linux/,它并不像您根据问题中的假设所期望的那么简单,它非常值得全面阅读。
许多实现中的 ThreadStack 大小都有最小限制,该限制因操作系统(有时甚至是 JVM 版本)而异;如果您将限制设置为低于 JVM 或操作系统的本机操作系统限制(有时必须设置 *nix 上的 ulimit),则线程堆栈设置将被忽略。其他命令行选项的工作方式相同,当提供的值太小时,默认为更高的值。不要假设传入的所有值都代表实际使用的值。
类加载器(Tomcat 有多个类加载器)会占用大量不易记录的内存。 JIT 消耗了大量内存,以空间换取时间,这在大多数情况下是一个很好的权衡。