我正在Java 5上编写一个客户端Swing应用程序(图形字体设计器)。最近,我遇到了Java .lang. outofmemoryerror: Java堆空间错误,因为我在内存使用上不保守。用户可以打开无限数量的文件,程序将打开的对象保存在内存中。在快速研究之后,我发现5.0 Java虚拟机和其他人说,在Windows机器上,JVM默认的最大堆大小为64MB。
在这种情况下,我应该如何处理这个约束呢?
我可以使用java的命令行选项增加最大堆大小,但这需要计算出可用的RAM并编写一些启动程序或脚本。此外,增加到某个有限最大值并不能最终摆脱这个问题。
我可以重写一些代码,频繁地将对象持久化到文件系统中(使用数据库也是一样),以释放内存。它可能会起作用,但可能也要做很多工作。
如果你能告诉我上述想法的细节或一些替代方案,如自动虚拟内存,动态扩展堆大小,那将是伟大的。
我想添加建议从甲骨文故障排除文章。
线程thread_name异常:Java .lang. outofmemoryerror: Java堆空间
详细消息Java堆空间表示无法在Java堆中分配对象。此错误并不一定意味着内存泄漏
可能的原因:
简单的配置问题,指定的堆大小不足以满足应用程序的要求。
应用程序无意中持有对对象的引用,这可以防止对象被垃圾收集。
过度使用终结符。
此错误的另一个潜在来源来自于过度使用终结器的应用程序。如果类具有finalize方法,则该类型的对象在垃圾收集时不会回收其空间
在垃圾收集之后,对象将排队等待终结,这将在稍后发生。终结器由服务终结队列的守护线程执行。如果终结器线程无法跟上终结队列,那么Java堆就会被填满,并抛出这种类型的OutOfMemoryError异常。
可能导致这种情况的一种场景是,应用程序创建了高优先级线程,导致终结队列的增长速度快于终结线程服务该队列的速度。
我在其他地方读到过,你可以尝试- catch java.lang.OutOfMemoryError,在catch块上,你可以释放所有你知道可能使用大量内存的资源,关闭连接等等,然后执行System.gc(),然后重新尝试你要做的任何事情。
另一种方式是,虽然,我不知道这是否会工作,但我目前正在测试它是否会在我的应用程序上工作。
这个想法是通过调用System.gc()来进行垃圾收集,这可以增加可用内存。您可以在内存消耗代码执行之后继续检查。
//Mimimum acceptable free memory you think your app needs
long minRunningMemory = (1024*1024);
Runtime runtime = Runtime.getRuntime();
if(runtime.freeMemory()<minRunningMemory)
System.gc();
最终,无论您在哪个平台上运行,您总是有一个有限的堆的最大值可以使用。在Windows 32位中,这大约是2GB(不是具体的堆,而是每个进程的总内存)。只是碰巧Java选择将默认值设得更小(大概是为了让程序员创建的程序在内存分配失控的情况下不会遇到这个问题,并且必须检查它们正在做什么)。
因此,这里有几种方法可以用来确定需要的内存量或减少正在使用的内存量。使用垃圾收集语言(如Java或c#)的一个常见错误是保留对不再使用的对象的引用,或者分配许多可以重用的对象。只要对象有对它们的引用,它们就会继续使用堆空间,因为垃圾收集器不会删除它们。
在这种情况下,您可以使用Java内存分析器来确定程序中的哪些方法正在分配大量对象,然后确定是否有办法确保它们不再被引用,或者从一开始就不分配它们。我过去使用的一个选项是“JMP”http://www.khelekore.org/jmp/。
如果您确定分配这些对象是出于某种原因,并且需要保持引用(取决于您正在做什么,可能是这种情况),那么在启动程序时只需增加最大堆大小。但是,一旦您执行了内存分析并了解对象是如何分配的,您就应该更好地了解您需要多少内存。
In general if you can't guarantee that your program will run in some finite amount of memory (perhaps depending on input size) you will always run into this problem. Only after exhausting all of this will you need to look into caching objects out to disk etc. At this point you should have a very good reason to say "I need Xgb of memory" for something and you can't work around it by improving your algorithms or memory allocation patterns. Generally this will only usually be the case for algorithms operating on large datasets (like a database or some scientific analysis program) and then techniques like caching and memory mapped IO become useful.