然而,我发现如果在应用程序的单个运行中,我打开和关闭数据集5次,总内存消耗会稳步增加,直到出现内存不足错误:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
6882 bguiz 20 0 679m 206m 19m S 30 13.7 0:30.22 java
6882 bguiz 20 0 679m 259m 19m S 9 17.2 0:55.53 java
6882 bguiz 20 0 679m 301m 19m S 9 20.0 1:20.04 java
6882 bguiz 20 0 679m 357m 19m S 33 23.7 1:44.74 java
6882 bguiz 20 0 679m 395m 19m S 80 26.2 2:10.31 java
内存从约14%增长到约26%。看起来像是内存泄漏。
正在发生的事情是,加载的顶级数据用于填充集合,例如地图和列表,然后更详细的数据用于创建这些顶级对象的子对象,然后它们又创建子子对象。
当数据集关闭时,当前应用程序确实会尝试通过去除各种对象的集合,然后显式调用System.gc();
来清除其痕迹。
无论如何,当我接手这个任务时(在我之前已经进行了几年),这就是应用程序的状态。
我需要做的是找到一种方法,找出哪些子对象和子子对象在卸载数据集后仍然相互引用,并加以纠正。
显然,这可以手动完成,但是非常非常繁琐,但我认为使用内存分析是更好的选择,这是我以前没有做过的事情。
我阅读了一些其他SO问题,询问要使用哪些内存分析工具,我选择了Netbeans IDE内置的工具,因为它似乎得到了很好的评价,并且我也在Netbeans中工作。
有人以前进行过类似的Java内存分析任务吗?有了经验教训:
- 你会给我什么具体的建议?
- 你发现哪些技术在解决这个问题时有用?
- 你发现哪些资源在解决这个问题时有用?
编辑: 此应用程序是标准桌面应用程序-不是Web应用程序。
编辑:已实施的解决方案
基本上对我有用的是使用Netbeans的分析器与JHAT。
我发现Netbeans IDE内置的分析器非常出色,可以在特定的分析点创建内存转储,然后该工具能够按类过滤和排序,并深入每个实例的引用。这一切都非常好。
但是,它没有为我提供比较两个堆转储的方法。我问了一个跟进问题,看起来JHAT(作为JDK的一部分)做得很好。
Thorbjørn Ravn Andersen、Dmitry和Jason Gritman:你们的意见真的很有帮助,不幸的是我只能标记1个正确答案,但你们都得到了我的+1。