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