2016-06-13 43 views
0

我的代码基本上在Apache Spark上运行,其中每个容器都在单独的JVM上运行。您为容器指定了一定的内存限制。在我的程序中,一个容器完成了一项任务,但是当它试图执行另一项任务时,它会崩溃,说超出了内存限制。如果我在单独的容器中运行每个任务,它们总是运行良好。所以,看起来在任务完成后留下了一些未关闭的资源,我无法在代码中找到它们,而这些未关闭的资源增加了容器的内存。所以,我的问题是,Java中有没有办法告诉JVM强制关闭所有资源。我也可以强制垃圾收集。我想在每项任务结束时执行这两个步骤。强制关闭Java中所有未关闭的资源

+1

不,你真的需要小心你的程序来清理不必要的对象。 Java仅为符合GC要求的对象释放内存(但在抛出OutOfMemory错误之前它可靠地执行此操作)。 – Thilo

+1

您可以让JVM在进入OOM时产生堆内存转储,以查看仍然存在的内容。有一个启动标志。 – Thilo

+0

您一般无法“关闭所有未关闭的资源”,因为您的程序可能仍在使用这些资源。正如@Thilo所提到的,堆转储来分析任何实际的泄漏可能是您最好的选择。 –

回答

2

您可以运行System.gc();但我怀疑这会帮助 - 内存不足时,将Java垃圾收集,只有失败如果这需要太长时间。但是你描述它的方式,你可能没有资源(=文件,套接字等)打开,但是大对象可达。确保返回的对象不会引用不必要的中间数据,也不会在static变量中存储除常量之外的任何内容。

使用例如visualvm或其他任何可以产生堆转储的内容来查找哪些对象支持您的内存。

我知道Scala没有这个功能。但Java 8具有自动闭合的外部资源,被称为尝试 - 与资源一个很好的功能:离开这个块时

try(AutoCloseable foo = openSomeResource()) { 
    doSomething(); 
} 

会自动调用foo.close();,无论怎样(例如例外,返回)。如果遵循这种模式,很难将资源保持开放。但是这指的是Java中所谓的“资源”,它们必须实现AutoCloseable接口,您可能没有打开资源,但可访问对象。假设有很多关于如何调试Java/Scala内存泄漏的教程。但通常,第一步是获得一个堆转储以查看正在使用多少内存。某些工具(例如hprof,内置的JVM)甚至可以使用行号显示分配站点

+0

我想,大对象是在静态变量中引用的,或者是从主要方法引用的地方。 – slartidan

+0

或在工作线程上的线程本地? – Det

+0

当方法返回时,应该调用main方法中的东西(除了可以从返回值中获得的东西!),当线程完成时,线程本地人应该变为不可达和GCable。我怀疑它只是返回值,保持对所有输入数据的引用。 –

0

也许你可以使用try-与资源在JDK7以上

try (BufferedReader br = new BufferedReader(new FileReader(path))) { 
     return br.readLine(); 
     }