JVM内存使用失控。

35 浏览
0 Comments

JVM内存使用失控。

我有一个Tomcat的Web应用程序,代表客户执行一些非常占用内存和CPU的任务。这是正常的,并且是期望的功能。然而,当我运行Tomcat时,内存使用量会随着时间的推移急剧增加,最高达到4.0GB,这时我通常会终止进程,因为它会影响我开发机器上运行的其他所有内容:\n我以为我的代码中不小心引入了内存泄漏,但在使用VisualVM进行检查后,我发现情况有所不同:\nVisualVM显示堆大约占用了1GB的内存,这是我使用设置的。\n为什么我的系统认为这个进程占用了大量内存,而根据VisualVM的显示,它几乎没有占用任何内存呢?\n


\n经过进一步的调查,我注意到如果应用程序中同时运行多个任务,内存不会被释放。然而,如果我在将另一个任务提交到由ExecutorService提供的BlockingQueue之前等待每个任务完成,那么内存将被有效地回收。我该如何调试这个问题?为什么垃圾回收/内存重用会有所不同?

0
0 Comments

JVM内存使用失控的问题可能是由于垃圾回收机制导致的。在解决这个问题之前,我们需要检查CPU使用率和垃圾收集器。垃圾回收暂停和CPU垃圾回收可能会进一步减慢机器的运行速度。

要解决JVM内存使用失控的问题,可以采取以下方法:

1. 增加堆内存大小:可以通过调整JVM的堆内存大小来解决内存使用过高的问题。通过增加堆内存大小,可以为JVM提供更多的内存空间,从而减少内存溢出的风险。可以通过在启动脚本中使用"-Xmx"选项来增加堆内存大小。

java -Xmx4g -jar myapp.jar

上述示例中,"-Xmx4g"表示将堆内存大小设置为4GB。

2. 优化垃圾回收:可以通过调整垃圾回收器的参数来优化垃圾回收的性能。可以使用不同的垃圾回收器,如Serial GC、Parallel GC、CMS GC和G1 GC,并根据应用程序的需求进行调整。可以通过在启动脚本中使用"-XX:+Use"选项来指定垃圾回收器。

java -XX:+UseG1GC -jar myapp.jar

上述示例中,"-XX:+UseG1GC"表示使用G1垃圾回收器。

3. 优化代码和资源使用:可以通过优化代码和资源使用来减少内存占用。可以检查代码中是否存在内存泄漏或不必要的资源占用,并进行相应的调整。可以使用内存分析工具来帮助检测和解决内存泄漏问题。

4. 使用内存监控工具:可以使用内存监控工具来监视JVM的内存使用情况。可以使用工具如VisualVM、JConsole和Java Mission Control来监控堆内存和非堆内存的使用情况,并进行相应的优化。

通过采取上述方法,可以有效地解决JVM内存使用失控的问题,并提高应用程序的性能和稳定性。

0
0 Comments

JVM内存使用失控的原因是无法控制所需的控制。-Xmx只控制Java堆,它无法控制JVM对本机内存的消耗,因为不同的实现方式完全不同。VisualVM只显示堆消耗,而不显示作为操作系统进程的整个JVM消耗的本机内存。您需要使用操作系统级工具来查看这一点,它们将报告完全不同的数字,通常远远大于VisualVM报告的任何数字,因为JVM以完全不同的方式使用本机内存。

来自以下文章:感谢记忆(了解JVM如何在Windows和Linux上使用本机内存)

保持堆和垃圾收集器使用本机内存,您无法控制。

更多的本机内存用于维护维护Java堆的内存管理系统的状态。必须分配数据结构来跟踪空闲存储并记录在收集垃圾时的进展情况。这些数据结构的确切大小和性质因实现而异,但许多与堆的大小成比例。

JIT编译器像javac一样使用本机内存

字节码编译使用本机内存(就像静态编译器(例如gcc)需要内存一样),但是JIT的输入(字节码)和输出(可执行代码)也必须存储在本机内存中。包含许多JIT编译方法的Java应用程序使用的本机内存比较小的应用程序更多。

然后,您还有使用本机内存的类加载器

Java应用程序由定义对象结构和方法逻辑的类组成。它们还使用来自Java运行时类库(例如java.lang.String)的类,并且可能使用第三方库。这些类需要在使用它们的期间存储在内存中。类的存储方式因实现而异。

我甚至不会引用关于线程的部分,我想您已经明白了-Xmx不控制您认为它控制的内容,它控制JVM堆,不是所有内容都放在JVM堆中,而堆占用的本机内存比您为管理和簿记指定的内存要多得多。

简而言之,JVM使用的内存比-Xms和-Xmx以及其他命令行参数中提供的内存更多。这是一个非常详细的关于JVM如何分配和管理内存的文章,根据您在问题中的假设,它并不像您期望的那样简单,值得全面阅读。

许多实现中的ThreadStack大小具有变化的最小限制,具体取决于操作系统,有时还取决于JVM版本;如果将限制设置为低于JVM或操作系统的本机OS限制,则会忽略threadstack设置(在*nix上的ulimit有时必须设置)。其他命令行选项的工作方式也相同,当提供的值过小时,它们会静默地默认为较高的值。不要假设传递的所有值都代表实际使用的值。

类加载器(Tomcat有一个以上)消耗了很多不容易记录的内存。JIT消耗了大量内存,以时间换空间,这通常是一个很好的权衡。

0