我读了很多书,但到目前为止读到的内容并没有多大意义,所以我在这里问一个关于 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
第一个问题:
- 为什么这些数字这么高?
- 如果我重新启动应用程序,它一开始的 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 内存的复杂性就会发挥作用:
RSS
负责处理驻留在内存中的所有页面,无论它们是用于 JVM 的私有数据还是文件和库的缓存部分。与 Java 的 GC 工作方式类似,当 Linux 内核的物理内存不足时,它会释放文件缓存。此外,许多页面可以在 JVM 之间共享DATA
测量所有进入进程虚拟空间的私有内存mmap
。其中大部分永远不会有任何底层物理内存。
如果要详细检查每个 JVM 的虚拟内存,请使用:
pmap -p <processes_pid> -x
或者对脏页进行排序的版本:
pmap -p <processes_pid> -x | sort -rnk 4
并且您可以看到是什么导致了这些RSS
数字DATA
。
编辑:您可以阅读更多有关 Linux 如何对内存进行分类以及许多工具给出的数字本网站