我有一个大型Java应用程序,它使用actionPerformed(下面的示例代码)内的try / catch处理大量数据文件。当我在循环中获取约1000个文件时,它会耗尽内存。
每个文件加载合法地占用大约1MB的存储空间,但是我仔细查看过,没有看到该存储空间被挂到的任何地方。每个文件加载都在做相同的事情(即分配相同的变量),因此应该重新使用而不是累加。
我尝试在循环中插入一个显式的gc调用,该调用(根据visualvm)仅能成功消除内存使用量的峰值(请参见下图)。
奇怪的是内存使用的行为:如所附图像所示,使用情况在加载循环工作时攀升,在try内停留在平稳状态,但是try外的gc导致回收所有内存(高原尽头的悬崖)。
关于try / catch是否有影响gc行为的内容?有关在我的代码中检查内容的任何提示,以查找可能引起的泄漏?
我花了很多时间使用各种内存/堆管理工具以及跟踪代码,这确实让我感到困惑。如果这是我的代码中真正的内存泄漏,为什么最终的gc会清除所有内容?
非常感谢您的任何建议/想法。
if (message == MenuCommands.TRYLOADINGFILES){
try {
File dir = new File(<directory with 1015 files in it>);
File [] cskFiles = dir.listFiles(ioUtilities.cskFileFilter);
for (int i=0; i<cskFiles.length; i++){
loadDrawingFromFile(cskFiles[i], true);
if (i % 10 == 0) System.gc();
}
DebugUtilities.pauseForOK("pausing inside try");
}
catch (Exception e1){
e1.printStackTrace();
}
DebugUtilities.pauseForOK("pausing outside try");
System.gc();
DebugUtilities.pauseForOK("pausing after gc, outside try");
}
哪里
public static pauseForOK(String msg){
JOptionPane.showMessageDialog(null, msg, "OK", JOptionPane.INFORMATION_MESSAGE);
}
后续根据彼得的建议,如下。 histo:live在运行时(在pgm启动时,在执行任何操作之前,在读取所有文件之后(当visualvm报告正在使用的存储GB时),在最终gc之后,当visualvm表示已恢复为最初的stg使用时)都几乎没有变化)。从启动到运行前四个类别大约增加一倍,Char stg的数量大约增加一个文件处理的预期数量,但其他没有太大变化。
据它看来,似乎没有任何东西在坚持。这是文件加载循环完成之后(在try之外的最终gc之前)之后的histo的前30行左右。
num #instances #bytes class name
----------------------------------------------
1: 67824 9242064 <methodKlass>
2: 67824 9199704 <constMethodKlass>
3: 6307 7517424 <constantPoolKlass>
4: 6307 6106760 <instanceKlassKlass>
5: 46924 5861896 [C
6: 5618 4751200 <constantPoolCacheKlass>
7: 10590 3944304 [S
8: 19427 3672480 [I
9: 15280 1617096 [B
10: 33996 1584808 [Ljava.lang.Object;
11: 2975 1487144 <methodDataKlass>
12: 40028 1280896 java.util.Hashtable$Entry
13: 45791 1098984 java.lang.String
14: 31079 994528 java.util.HashMap$Entry
15: 10580 973472 [Ljava.util.HashMap$Entry;
16: 6750 817344 java.lang.Class
17: 10427 583912 java.util.HashMap
18: 1521 523224 javax.swing.JPanel
19: 10008 516344 [[I
20: 8291 457176 [Ljava.security.ProtectionDomain;
21: 4022 431800 [Ljava.util.Hashtable$Entry;
22: 774 377712 com.sun.java.swing.plaf.windows.WindowsScrollBarUI$WindowsArrowButton
23: 689 369704 [J
24: 13931 334344 java.util.ArrayList
25: 7625 305000 java.util.WeakHashMap$Entry
26: 8611 275552 java.lang.ref.WeakReference
27: 8501 272032 java.security.AccessControlContext
28: 16144 258304 javax.swing.event.EventListenerList
29: 6141 245640 com.sun.tools.visualvm.attach.HeapHistogramImpl$ClassInfoImpl
30: 426 245376 <objArrayKlassKlass>
31: 3937 220472 java.util.Hashtable
32: 13395 214320 java.lang.Object
33: 2267 199496 javax.swing.text.html.InlineView
无论运行在什么时候,它基本都显示了同一件事。即使没有:live参数,结果也基本相同。但是,如果程序在足够的文件上运行,则肯定会耗尽内存。
另一件事:我使用visualvm的Memory Sampling拍摄了两个快照,一个在pgm starup上拍摄,另一个在内存使用的稳定期拍摄;增量显示了存储使用的预期增长,其中包括与处理的文件数完全相同的某些结构的数量增加。每次文件处理都会创建这些结构之一,就好像所有中间存储都在尝试期间都保留着一样,但是可以在以后清除。
这是怎么回事?
++++++++++++
美国东部时间周日22:00更新
感谢@Peter Lowrey,@ Vampire和其他人的建议。尝试了所有这些想法,但没有任何效果。尝试设置-XX:NewSize = 1GB和-XX:NewRatio = 3,但没有帮助。
try / catch是原始代码的保留,在示例中(我迟来了)是无关紧要的。摆脱它完全不会改变任何事情。只是简单的for循环加载文件会导致相同的内存增长模式,然后是删除
完成最终gc时,将其设置为初始值。
遵循@Vampire的建议,我尝试了此变体(内嵌负载,而不是块内加载):
loadDrawingFromFile(thecskFile, true);
loadDrawingFromFile(thecskFile, true);
... 20 times
DebugUtilities.pauseForOK("after 20 loads, before gc");
System.gc();
DebugUtilities.pauseForOK("after gc outside try");
与整个示例中一样,这20个文件加载在Used Heap空间中所产生的增长量成比例地相同(大约400MB),然后在上面的System.gc()之后,所使用的堆空间立即下降到程序初始化级别,就像之前一样。
发生这种情况时,我尝试了一种更基本的方法
loadDrawingFromFile(thecskFile, true);
DebugUtilities.pauseForOK("after load ");
System.gc();
.. repeated 20 times
从某种意义上说,完成这项工作的意义是,即使加载20个文件,内存使用量也永远不会达到50 MB。
因此,这似乎与线程和线程中断有关。这使我不得不提一个事实:这是一个运行在以以下内容开头的GUI上的应用程序:
SwingUtilities.invokeLater(new Runnable() {
public void run() { ... }
}
我对线程和Swing实用工具不那么熟悉,所以这也许是天真的错误,但这似乎可以归结为一个事实,即在ShowMessageDialog之前,gc不会触摸很多非活动对象。打断某事。
欢迎其他建议。
最佳答案
我怀疑您没有内存泄漏。取而代之的是您过早地推广大对象。
如果您要创建大型对象,例如byte [],它们直接进入租用空间。这些仅在主要或完整集合中清除。最有可能的是,您仅触发次要集合,而不会触发大型对象,直到触发完整集合为止。
关于java - 可能的尝试/捕获和内存管理问题?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23875078/