java - java进程随着时间的推移消耗更多内存但没有内存泄漏
问题描述
我的 java 服务在 16 GB RAM 主机上运行, -Xms 和 -Xmx 设置为 8GB。主机正在运行其他一些进程。
我注意到我的服务随着时间的推移会消耗更多的内存。ps aux | awk '{print $6/1024 " MB\t\t" $11}' | sort -n
我在主机上运行了这个命令并记录了我的 java 服务的内存使用情况。
服务启动时,它使用了大约 8GB 内存(因为 -Xms 和 -Xmx 设置为 8GB),但一周后,它使用了大约 9GB+ 内存。它每天消耗大约 100MB 更多的内存。
我做了一个堆转储。我重新启动了服务并进行了另一个堆转储。我比较了这两个转储,但堆使用量没有太大差异。转储显示该服务在重新启动前使用了大约 1.3GB,在重新启动后使用了大约 1.1GB。
从进程内存使用情况来看,我的服务随着时间的推移消耗了更多内存,但堆转储中没有报告。如何识别服务中内存使用量的增加?
我将 -Xms 和 -Xmx 设置为 8GB。主机有 16GB 内存。我是否将最小/最大堆设置得太高(主机上总内存的 50%)?这会引起任何问题吗?
解决方案
好的,您已经告诉 JVM,它最多可以为堆使用 8GB,并且您观察到总内存使用量从 1.1GB 增加到 1.3GB。这本身并不是一个迹象或问题。当然,JVM 并没有像您所说的那样使用任何地方的内存。
要注意的第二件事是尚不清楚您如何测量内存使用情况。您应该知道 JVM 使用大量内存,而不是 Java 堆内存。这包括:
java
可执行文件本身使用的内存。- 用于保存本机库的内存。
- 用于保存字节码和 JIT 编译的本机代码的内存(在“元空间”中)
- 线程堆栈
- (通常)本机代码请求的堆外内存分配。
- 内存映射文件和共享内存段。
报告了其中的一些用法(如果您使用正确的工具)。
第三件事是 Java 堆实际使用的内存可能会有很大差异。GC 通常通过将活动对象从一个“空间”复制到另一个来工作,因此它需要大量的可用空间来执行此操作。然后,一旦完成运行,GC 就会查看(现在)有多少可用空间与已用空间的比率。如果该比率太小,它会向操作系统请求更多内存。因此,即使实际使用量(在非垃圾对象中)只是逐渐增加,总内存使用量也可能会大幅增加。由于各种“热身”效应,这对于最近才启动的 JVM 来说很可能。
最后,您提供的证据并没有说(对我来说!)没有内存泄漏。我认为您需要将堆转储进一步分开。我建议在启动后 2 小时进行一次转储,然后在 2 小时或更长时间后进行第二次转储。这会给你足够的“泄漏”来显示在转储的比较中。
从进程内存使用情况来看,我的服务随着时间的推移消耗了更多内存,但堆转储中没有报告。如何识别服务中内存使用量的增加?
我不认为你需要这样做。我认为总体内存使用量从 1.1GB 增加到 1.3GB 是一个红鲱鱼。
相反,我认为您应该关注其他证据所指向的内存泄漏。见我上面的建议。
我是否将最小/最大堆设置得太高(主机上总内存的 50%)?这会引起任何问题吗?
嗯......当堆满时,更大的堆将会有更明显的性能下降。另一方面,更大的堆意味着填充需要更长的时间......假设您有内存泄漏......这意味着诊断问题可能需要更长的时间,或者确保您已修复它。
但另一方面,这可能根本不是内存泄漏。它也可能是您的应用程序或第三方库缓存的东西。正确实现的缓存可能会使用大量内存,但如果堆太接近满,它应该通过断开链接1并逐出缓存数据来响应。因此,不是内存泄漏......假设。
1 - 或者如果你使用SoftReference
s,GC 会为你破坏它们。
推荐阅读
- python - 使用 numpy.random.exponential 抽取 10,000,000 个 X 样本来估计支出的预期值
- postgresql - postgresql:第一次创建数据库和用户:多个选项
- react-native - 如何在本机反应中使用渐变
- spring-boot - 使用编程 bean 注册检索自动配置
- matlab - Matlab服务员“取消”按钮不会响应
- php - 根据 Mysql 结果更改样式(即 - 对于返回的每个名称)
- javascript - 正则表达式应该只接受 5 个只有 7 个字母
- typescript - TypeScript:通过从 Array 扩展的类型中的连接来跟踪所需的字符串文字类型
- c - 如何修复“堆已损坏”运行时错误?
- android - 嵌套枚举条目