Java程序的内存消耗问题

olm*_*ath 17 java memory

我有一个在我的Ubuntu 10.04机器上运行的Java程序,在没有任何用户交互的情况下,反复查询MySQL数据库,然后根据从DB读取的数据构造img和txt文件.它可以进行数万次查询并创建数万个文件.

运行几个小时后,我的机器上的可用内存(包括交换空间)已经完全耗尽.我还没有启动其他程序,并且在后台运行的进程不会消耗太多内存,也不会真正增加消耗.

为了找出分配如此多内存的内容,我想分析一个堆转储,所以我用-Xms64m -Xmx128m -XX:+ HeapDumpOnOutOfMemoryError启动了这个过程.

令我惊讶的是,情况与以前一样,经过几个小时后,程序正在分配所有交换,这超出了给定的最大值128米.

用VisualVM调试的另一个运行显示堆分配永远不会超过最大128m - 当分配的内存接近最大值时,它的很大一部分再次释放(我假设是垃圾收集器).

因此,稳定增长的堆不会成为问题.

当内存全部耗尽时:

免费显示以下内容:

             total       used       free     shared    buffers     cached
Mem:       2060180    2004860      55320          0        848    1042908
-/+ buffers/cache:     961104    1099076
Swap:      3227640    3227640          0
Run Code Online (Sandbox Code Playgroud)

top显示以下内容:

USER    VIRT    RES     SHR     COMMAND
[my_id] 504m    171m    4520    java
[my_id] 371m    162m    4368    java
Run Code Online (Sandbox Code Playgroud)

(到目前为止,两个"最大"进程和唯一运行的java进程)

我的第一个问题是:

  • 如何在操作系统级别(例如使用命令行工具)找到分配如此多内存的内容?top/htop没有帮助我.在许多情况下,许多相同类型的微小进程占用了内存:有没有办法智能地总结类似的进程?(我知道这可能不是主题,因为它是Linux/Ubuntu问题,但我的主要问题可能仍然是与Java相关)

我的老问题是:

  • 为什么不在顶部输出中给出我程序的内存消耗?
  • 如何找出分配如此多内存的内容?
  • 如果堆不是问题,堆栈的唯一"分配因素"是什么?(堆栈不应该是一个问题,因为没有深层"方法调用深度")
  • 外部资源作为数据库连接怎么样?

max*_*dim 7

如果你的Java进程确实占用内存并且VisualVM或内存转储中没有任何疑问,那么它必须在本机代码中的某个地方 - 无论是在JVM中还是在你正在使用的某些库中.例如,在JVM级别上,如果您使用的是NIO或内存映射文件.如果您的某些库正在使用本机调用,或者您正在使用不为您的数据库键入4个JDBC驱动程序,则可能存在泄漏.

一些建议:

  • 还有一些细节如何查找内存泄漏在本机代码在这里.好也.
  • 像往常一样,确保正确关闭所有资源(文件,流,连接,线程等).其中大多数都是在某些时候调用本机实现,因此消耗的内存可能无法在JVM中直接显示
  • 检查操作系统级别消耗的资源 - 打开文件的数量,文件描述符,网络连接等.


olm*_*ath 0

由于在我提出问题的那天之后(直到 3 月 23 日)没有任何活动,而且我仍然找不到内存消耗的原因,所以我务实地“解决”了这个问题。

导致问题的程序基本上是“任务”的重复(即查询数据库然后创建文件)。对程序进行参数化相对容易,以便执行任务的某个子集而不是全部。

所以现在我从 shell 脚本重复运行我的程序,在每个进程中仅执行一组任务(通过参数进行参数化)。最后,所有任务都被执行,但由于单个进程仅处理任务的子集,因此不再存在内存问题。

对我来说这是一个足够的解决方案。如果您有类似的问题并且您的程序具有类似批处理的执行结构,这可能是一种实用的方法。

当我有时间时,我会研究新的建议,希望找出根本原因(感谢您的帮助!)。