Java 内存有限,但仍然占用太多 RAM

Java 内存有限,但仍然占用太多 RAM

我读了很多书,但到目前为止读到的内容并没有多大意义,所以我在这里问一个关于 Java 和内存的新问题。

因此,我使用以下 CLI 参数启动 Java 应用程序

-Xms48m
-Xmx96m
-XX:MetaspaceSize=80m
-XX:MaxMetaspaceSize=150m

在我的应用程序中,我有一些类似的代码来显示已用的内存:

Runtime runtime = Runtime.getRuntime();
//Used mem: runtime.totalMemory() - runtime.freeMemory()
//Total mem: runtime.totalMemory()
//Max mem: runtime.maxMemory()

结果正如预期:

Used Memory: 43 mb
Free Memory: 16 mb
Total Memory: 60 mb
Max Memory: 96 mb

我还运行了垃圾收集器,进行了堆转储并进行了分析,它也说使用了大约 43MB。

到目前为止,这部分还不错。但是现在,如果我htop在 Linux 上运行该命令,我会得到 Java 应用程序的以下数字:

RES: 409M
DATA: 611M

第一个问题:

  1. 为什么这些数字这么高?
  2. 如果我重新启动应用程序,它一开始的 RES:224M,DATA:339M,然后不断增长,直到一天后达到上面提到的 409M/611M,然后我使用 cron 作业重新启动应用程序,否则我的 RAM 就会用完。我该如何防止这种情况发生?

(我在具有 32GB RAM 的服务器上运行了 80 个同一应用程序的实例)。

以下是该情况的截图: 在此处输入图片描述

平台:

  • 操作系统:Ubuntu 16.04.6 LTS

  • Java:OpenJDK 运行环境(build 1.8.0_232-8u232-b09-0ubuntu1~16.04.1-b09)/OpenJDK 64 位服务器 VM(build 25.232-b09,混合模式)

  • Java 应用程序:Play Framework v2.7 应用程序

答案1

在分析 Java 内存使用情况时,您忘记了 使用的内存大小DirectBuffer。您可以使用 来控制它-XX:MaxDirectMemorySize,它默认为最大堆大小。

在最坏的情况下,您允许 Java 使用 342 MiB 内存来存储其数据和一些其他次要内存区域。您可以在以下位置找到所有内存区域的描述贝尔登

当您开始分析实际内存消耗时,您还需要考虑 Java 库的大小,这个库并不大,但jvm.so大约占 20 MiB。所有这些都相当于RSS您引用的数字。

然而,如果你想检查你的系统是否能够维持如此多的 JVM,Linux 内存的复杂性就会发挥作用:

  1. RSS负责处理驻留在内存中的所有页面,无论它们是用于 JVM 的私有数据还是文件和库的缓存部分。与 Java 的 GC 工作方式类似,当 Linux 内核的物理内存不足时,它会释放文件缓存。此外,许多页面可以在 JVM 之间共享
  2. DATA测量所有进入进程虚拟空间的私有内存mmap。其中大部分永远不会有任何底层物理内存。

如果要详细检查每个 JVM 的虚拟内存,请使用:

pmap -p <processes_pid> -x

或者对脏页进行排序的版本:

pmap -p <processes_pid> -x | sort -rnk 4

并且您可以看到是什么导致了这些RSS数字DATA

编辑:您可以阅读更多有关 Linux 如何对内存进行分类以及许多工具给出的数字本网站

相关内容