java - JVM内存使用失控

标签 java jvm visualvm

我有一个 Tomcat 网络应用程序,它代表客户执行一些内存和 CPU 密集型任务。这是正常的并且是所需的功能。但是,当我运行 Tomcat 时,内存使用量会随着时间的推移而飙升至 4.0GB 以上,此时我通常会终止该进程,因为它会干扰我开发机器上运行的所有其他内容:

enter image description here

我以为我的代码无意中引入了内存泄漏,但在使用 VisualVM 检查它之后,我看到了一个不同的故事:

enter image description here

VisualVM 显示堆占用了大约 1 GB 的 RAM,这是我用 CATALINA_OPTS="-Xms256m -Xmx1024" 设置的。

为什么我的系统将此进程视为占用大量内存,而根据 VisualVM,它几乎不占用任何内存?


经过一些进一步的探索,我注意到如果多个作业在应用程序中同时运行,内存不会被释放。但是,如果我等待每个作业完成,然后再将另一个作业提交到由 ExecutorService 提供服务的 BlockingQueue,那么内存将得到有效回收。我该如何调试呢?为什么垃圾收集/内存重用会有所不同?

最佳答案

你无法控制你想控制的东西-Xmx 只控制 Java 堆,它不控制 native 内存的消耗 由 JVM,根据实现完全不同地使用它。 VisualVM 仅向您显示堆正在消耗什么,它不会显示整个 JVM 作为操作系统进程消耗的 native 内存。您将不得不使用操作系统级别的工具来查看,它们将报告截然不同的数字,通常比 VisualVM 报告的任何数字都大得多,因为 JVM 以完全不同的方式使用 native 内存

来自以下文章Thanks for the Memory ( Understanding How the JVM uses Native Memory on Windows and Linux )

维护堆和垃圾收集器使用您无法控制的 native 内存。

More native memory is required to maintain the state of the memory-management system maintaining the Java heap. Data structures must be allocated to track free storage and record progress when collecting garbage. The exact size and nature of these data structures varies with implementation, but many are proportional to the size of the heap.

并且 JIT 编译器使用 native 内存,就像 javac 一样

Bytecode compilation uses native memory (in the same way that a static compiler such as gcc requires memory to run), but both the input (the bytecode) and the output (the executable code) from the JIT must also be stored in native memory. Java applications that contain many JIT-compiled methods use more native memory than smaller applications.

然后你有使用 native 内存的类加载器

Java applications are composed of classes that define object structure and method logic. They also use classes from the Java runtime class libraries (such as java.lang.String) and may use third-party libraries. These classes need to be stored in memory for as long as they are being used. How classes are stored varies by implementation.

我什至不会开始引用关于线程的部分,我想你明白了 -Xmx 并没有控制你认为它控制的东西,它控制的是 JVM 堆,而不是一切 进入 JVM 堆,堆占用比您指定的更多的 native 内存 管理和簿记。

Plain and simple the JVM uses more memory than what is supplied in -Xms and -Xmx and the other command line parameters.

这是一个very detailed article on how the JVM allocates and manages memory ,它并不像您根据问题中的假设所期望的那样简单,非常值得全面阅读。

许多实现中的 ThreadStack 大小都有最小限制,该限制因操作系统和有时 JVM 版本而异;如果您将限制设置为低于 JVM 或操作系统的 native 操作系统限制(有时必须设置 *nix 上的 ulimit),则忽略线程堆栈设置。其他命令行选项的工作方式相同,当提供的值太小时默认为更高的值。不要假设所有传入的值都代表实际使用的值。

类加载器,而 Tomcat 有多个,会占用大量内存,而这些内存不容易记录下来。 JIT 会占用大量内存,以空间换取时间,这在大多数情况下是一个很好的权衡。

关于java - JVM内存使用失控,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11768615/

相关文章:

java - 视觉虚拟机/j视觉虚拟机 : not supported for this JVM

java - build() 方法对 JAX-RS 中的响应做什么?

jvm - hprof 中具有 "no references"的对象

JavaFX 2 组合框在 win xp 中不起作用

java - 对 BLOB 进行操作需要太多时间

java - 鼓励 JVM 进行 GC 而不是增加堆?

java - 通过 JVM TI 代理将 invokestatic 添加到 java/lang/Object.<init> 会导致 JVM 因段错误而崩溃

java - 如何通过 JMX 监控 spring-boot 应用程序?

java - Java中的线程同步

java - 我的项目中有 NaN 错误已编辑