【问题标题】:Forcefully close all unclosed resources in Java强制关闭 Java 中所有未关闭的资源
【发布时间】:2016-06-13 05:45:22
【问题描述】:

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

【问题讨论】:

  • 不,您确实需要在程序中小心清理不必要的对象。 Java 只会为符合 GC 条件的对象释放内存(但它会在抛出 OutOfMemory 错误之前可靠地执行此操作)。
  • 您可以让 JVM 在进行 OOM 以查看仍然存在的内容时生成堆内存转储。有一个启动标志。
  • 您通常不能“关闭所有未关闭的资源”,因为这些资源可能仍在您的程序中使用。正如@Thilo 提到的,分析任何实际泄漏的堆转储可能是您最好的选择。

标签: java scala apache-spark


【解决方案1】:

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

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

我知道 Scala 没有这个功能。但是 Java 8 有一个很好的自动关闭外部资源的特性,称为 try-with-resources:

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

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

【讨论】:

  • 我想,大对象是在静态变量中引用的,或者在 main 方法的某个地方。
  • 当方法返回时应该对 main 方法中的东西进行 GC(除了可以从返回值到达的任何东西!)线程本地应该在线程完成时变得不可访问和 GCable。我怀疑它只是返回值保持对所有输入数据的引用。
【解决方案2】:

也许你可以在 jdk7 或更高版本中使用 try-with-resources

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

【讨论】:

    猜你喜欢
    • 2011-03-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多