我有一个在我的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进程)
我的第一个问题是:
我的老问题是:
如果你的Java进程确实占用内存并且VisualVM或内存转储中没有任何疑问,那么它必须在本机代码中的某个地方 - 无论是在JVM中还是在你正在使用的某些库中.例如,在JVM级别上,如果您使用的是NIO或内存映射文件.如果您的某些库正在使用本机调用,或者您正在使用不为您的数据库键入4个JDBC驱动程序,则可能存在泄漏.
一些建议:
由于在我提出问题的那天之后(直到 3 月 23 日)没有任何活动,而且我仍然找不到内存消耗的原因,所以我务实地“解决”了这个问题。
导致问题的程序基本上是“任务”的重复(即查询数据库然后创建文件)。对程序进行参数化相对容易,以便执行任务的某个子集而不是全部。
所以现在我从 shell 脚本重复运行我的程序,在每个进程中仅执行一组任务(通过参数进行参数化)。最后,所有任务都被执行,但由于单个进程仅处理任务的子集,因此不再存在内存问题。
对我来说这是一个足够的解决方案。如果您有类似的问题并且您的程序具有类似批处理的执行结构,这可能是一种实用的方法。
当我有时间时,我会研究新的建议,希望找出根本原因(感谢您的帮助!)。
| 归档时间: |
|
| 查看次数: |
6044 次 |
| 最近记录: |