2011-12-15 161 views
1

我创建的服务将不断运行,每天在指定的时间运行程序的主体。Java内存泄漏

本质:

while(true){ 
run(); 
Thread.sleep(day); 
} 

一段时间后,我越来越OutOfMemoryHeapExceptions。 在阅读了这篇文章之后,我想到了它,因为run()方法内创建的任何对象都不会被垃圾收集。

所以我做一样的东西:

public void run(){ 
Object a = new Object(); 
a.doSomething(); 

a= null; //Wasn't here before 
} 

我的问题是,这将解决我的问题?我的印象是,一旦对象为空,它以前引用的对象将被垃圾收集?这是一个好主意吗?或者我应该看看做别的事情?

谢谢

+0

东西没有人回答指出运行内存,虽然它是一个微弱的可能性:你可能已经打在VM或GC的错误。这不太可能,但并非不可能。 – Romain 2011-12-15 12:10:06

回答

3

添加a = null几乎肯定不足以解决问题(因为a即将超出范围)。

我的建议是使用内存分析器来查明什么是泄漏和在哪里。我个人使用YourKit。这非常好,但花钱(你可以得到免费的评估)。

另一个最近发布的工具是Plumbr。我还没有尝试它,但blurb说:

试试我们的Java代理以及时发现内存泄漏。我们会告诉您泄漏的是什么,泄漏源自哪里以及泄漏对象当前所在的位置 - 远在OutOfMemoryError之前!

0

您的印象不正确。在run()方法中创建的对象将被垃圾收集,只要它们1)超出范围,并且2)已经释放了它们正在使用的任何本地或远程系统资源。

你在run()方法调用中实际执行了哪些功能?你正在阅读文件,进行数据库调用,写入套接字?不知道细节很难提供更好的建议。

+0

那么,如果`a.doSomething()`添加对由`a`引用的对象的引用,在退出run()`的范围后仍然有效,该怎么办? – Romain 2011-12-15 12:05:59

+0

我从文件中提取信息,然后将它们插入到数据库中。 – Craig 2011-12-15 12:08:31

+0

@Romain - 如果这些引用不在run()的范围之内,并且与其他实时代码隔离,并且没有保留任何系统资源,我会希望它们正常进行GC'd。在这种情况下,我猜是有文件或数据库句柄保持不变。 – mcfinnigan 2011-12-15 13:01:36

0

你应该得到一个内存转储并使用类似 JConsole JVisualVM的工具进行分析。

run()方法的范围留在Thread.sleep(day);之前,因此该方法内的任何变量都被销毁。之后,a将不再存在,因此该变量引用的对象可能有资格进行垃圾回收,前提是没有其他引用

分析内存转储应该允许您找到对这些对象的任何引用(如果它们仍然存在)。

它可能不是那些物体,但其他的物体会保持活力,并且会消耗记忆。这取决于你在做什么,可能很难在这里分析。因此,根据内存使用情况查找大型对象图。

例如,我们遇到了经常创建的数据库连接问题(XA恢复机制),我们认为一旦方法范围被遗留,它们就会被销毁。但是,服务器将这些连接放入一个静态列表中,并且从未清除它,因此我们最终没有真正记忆。什么帮助我们识别出该案件正在分析内存转储。 :)

0

不,您不需要将该变量设置为空。虚拟机知道你退出了这个范围,并且变量a不再存在,所以它会自动减少引用计数,如果没有其他引用,你的对象可以被垃圾回收所取代。

该错误是在别的地方。

2

这可能确实有帮助,在某些情况下,GC算法需要一点帮助来执行,但它不能保证解决您的问题,只是延迟它们。

我的建议: 用较短的时间周期模拟相同的行为,以便强制发生错误。 用分析器运行它并查看所有内存在哪里,然后从那里开始工作。

0

将引用设置为null取决于您的对象是否处于长时间消耗过程中的范围内,尽管从理论上讲,它将标记引用为null,但不能保证它何时进行垃圾回收。

你需要检查你的对象是否在你的代码中的某个地方被长期保存。

发现设置参数的一个很好的解释为null:Does setting Java objects to null do anything anymore?

为了角球开出您的问题,您需要配置您的应用程序。

搜索等都给垃圾收集如此多的三分球,我决定只将搜索字符串在这里:

https://stackoverflow.com/search?q=Java+Garbage+collection+and+setting+references+to+null

http://java.sun.com/docs/books/performance/1st_edition/html/JPAppGC.fm.html

0

局部变量应该由GC收集。所以,你不需要把obj = null;。因为Object也存储在Heap区域。

0

在短期内,保持应用程序稳定的实用方法是在每次执行后退出JVM。使用批量调度程序(例如,在Windows上的* nix,at上的cron)每天只执行一次应用程序。任何内存泄漏都会在J​​VM存在时被清除。但是,您可能必须小心,不要让数据库连接处于打开状态等。

这会给您时间解决和修复潜在的内存泄漏问题,同时保持您的生产代码运行并且不需要支持人员重新启动服务器等等

我假设你不是一个执行