强制关闭Java中所有未关闭的资源

强制关闭Java中所有未关闭的资源,java,scala,apache-spark,Java,Scala,Apache Spark,我的代码基本上运行在ApacheSpark上,其中每个容器都运行在单独的JVM上。为容器指定特定的内存限制。在我的程序中,容器很好地完成了一项任务,但当它试图执行另一项任务时,它崩溃了,说超出了内存限制。如果我在单独的容器中运行每个任务,它们总是运行良好。因此,在任务完成后,似乎有一些未关闭的资源遗留下来,这在代码中是无法理解的,这些未关闭的资源增加了容器的内存。所以,我的问题是,Java中是否有任何方法可以告诉JVM强制关闭所有资源。我也可以强制垃圾收集。我希望在每个任务结束时执行这两个步骤。

我的代码基本上运行在ApacheSpark上,其中每个容器都运行在单独的JVM上。为容器指定特定的内存限制。在我的程序中,容器很好地完成了一项任务,但当它试图执行另一项任务时,它崩溃了,说超出了内存限制。如果我在单独的容器中运行每个任务,它们总是运行良好。因此,在任务完成后,似乎有一些未关闭的资源遗留下来,这在代码中是无法理解的,这些未关闭的资源增加了容器的内存。所以,我的问题是,Java中是否有任何方法可以告诉JVM强制关闭所有资源。我也可以强制垃圾收集。我希望在每个任务结束时执行这两个步骤。

也许您可以使用jdk7或更多版本中的try with resources

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

也许您可以在jdk7或更多版本中使用try-with资源

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

您可以运行
System.gc()
但我怀疑它是否有帮助——当内存不足时,Java会进行垃圾收集,只有当这需要太长时间时才会失败。但是按照您的描述,您可能没有打开的资源(=文件、套接字等),但是可以访问大型对象。确保返回的对象不引用不必要的中间数据,并且在
静态
变量中不存储除常量以外的任何内容

使用例如
visualvm
或任何其他可以产生堆转储的方法来查找占用内存的对象

我知道Scala没有这个功能。但是Java 8有一个很好的自动关闭外部资源的功能,称为“尝试使用资源”:

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

将自动调用
foo.close()离开此块时,无论如何(例如异常、返回)。如果遵循这种模式,很难让资源保持开放状态。但这指的是Java中所谓的“资源”,这些资源必须实现
自动关闭
接口,您可能没有打开的资源,但是可以访问的对象。应该有很多关于如何调试Java/Scala内存泄漏的教程。但通常第一步是获取堆转储,以查看使用了多少内存。某些工具(例如hprof、内置JVM)甚至可以用行号显示分配站点。

您可以运行
System.gc()
但我怀疑它是否有帮助——当内存不足时,Java会进行垃圾收集,只有当这需要太长时间时才会失败。但是按照您的描述,您可能没有打开的资源(=文件、套接字等),但是可以访问大型对象。确保返回的对象不引用不必要的中间数据,并且在
静态
变量中不存储除常量以外的任何内容

使用例如
visualvm
或任何其他可以产生堆转储的方法来查找占用内存的对象

我知道Scala没有这个功能。但是Java 8有一个很好的自动关闭外部资源的功能,称为“尝试使用资源”:

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

将自动调用
foo.close()离开此块时,无论如何(例如异常、返回)。如果遵循这种模式,很难让资源保持开放状态。但这指的是Java中所谓的“资源”,这些资源必须实现
自动关闭
接口,您可能没有打开的资源,但是可以访问的对象。应该有很多关于如何调试Java/Scala内存泄漏的教程。但通常第一步是获取堆转储,以查看使用了多少内存。某些工具(例如hprof、内置JVM)甚至可以用行号显示分配站点。

不,您确实需要在程序中小心清理不必要的对象。Java只为符合GC条件的对象释放内存(但它在抛出OutOfMemory错误之前可靠地做到了这一点)。您可以让JVM在运行OOM时生成堆内存转储,以查看仍然存在的内存。有一个启动标志。一般来说,您不能“关闭所有未关闭的资源”,因为这些资源可能仍被您的程序使用。正如@Thilo提到的,用堆转储来分析任何实际的泄漏可能是你最好的选择。不,你真的需要在程序中小心清理不必要的对象。Java只为符合GC条件的对象释放内存(但它在抛出OutOfMemory错误之前可靠地做到了这一点)。您可以让JVM在运行OOM时生成堆内存转储,以查看仍然存在的内存。有一个启动标志。一般来说,您不能“关闭所有未关闭的资源”,因为这些资源可能仍被您的程序使用。正如@Thilo所提到的,分析任何实际泄漏的堆转储可能是最好的选择。我想,大型对象在静态变量中引用,或者在主方法的某个地方引用。当方法返回时,主方法中的内容应该被GCed(从返回值中可以访问的内容除外!)当线程结束时,线程局部变量可能变得不可访问和GCable。我怀疑这只是因为返回值保留了对所有输入数据的引用。我想,大型对象是在静态变量中引用的,或者是在主方法的某个地方引用的。当方法返回时,应该对主方法中的内容进行GCed(从返回值中可以访问的内容除外!)当线程结束时,线程局部变量可能变得不可访问和GCable。我怀疑它只是简单地返回值,保留对所有输入数据的引用。