闭包内的对象生命周期

时间:2018-05-27 06:05:36

标签: scala apache-spark jvm

假设一个闭包已经在JVM中运行并在这个闭包范围内创建了一个对象,在JVM没有终止的情况下关闭执行后该对象是否仍然保留在JVM堆空间中?

一旦情况出现在Spark中 我使用下面的代码在执行程序中创建HBase连接:

rdd.foreachPartition(par => {

    # create a connection here.
    val connection = ConnectionFactory.createConnection(conf)

    par.foreach(item => {
        ...
    })

    # close this connection.
    connection.close()
})

显然,在执行程序中创建了连接。

  • 完成这项任务后,如果我从未关闭此连接,会发生什么事?

  • 如果火花推测在连接激活时杀死此任务怎么办? JVM仍将保持连接?

2 个答案:

答案 0 :(得分:2)

我认为这不是关于Spark的,而是一般的JVM。

首先,在函数范围内创建的变量只不过是局部变量。因此,在范围结束后,该局部变量没有引用,并且符合GC的条件。因此,在您的特定情况下,如果您的connection项目没有正确调用close()(由于,可能之间发生了一些异常),connection对象将被收集GC但连接本身并未关闭。我们将此情况称为连接泄漏。

处理此问题的最佳做法之一是确保每个连接都应该由try...finally关闭,Java8可以通过try-with-resource进行简短的手动调用。对于Scala,可以创建一个等效结构,有关详细信息/所学课程,请参阅this post

关于你的上一个问题,

  

如果火花猜测在连接激活时杀死此任务怎么办? JVM还会保持连接吗?

JVM将不再适当地保持连接。当此连接未被对等方明确关闭时,另一个对等方(服务器端)不知道它是否应该相应地关闭它直到某个空闲超时。无论如何,try finally可以涵盖所有情况,以确保正确清理所有连接。

答案 1 :(得分:1)

对象生命周期不与闭包的生命周期绑定,也就是说,它可以比它更长。一旦没有从其他对象引用,垃圾收集器就会回收该对象(考虑到,从Scala 2.11开始,闭包被实现为匿名内部类)。

为了防止资源泄漏,您可以使用所谓的贷款模式,您可以在其中管理资源的生命周期并确保在使用后(或之后)将其释放发生错误):

def withConnection[A](manage: () => Connection)(use: Connection => A): A = {
  val connection = manage()
  try {
    use(connection)
  } finally {
    connection.close()
  }
}

rdd.foreachPartition(p =>
  withConnection(ConnectionFactory.createConnection(conf)) { conn =>
    p.foreach(item => {
      ??? // your code
    })
  }

Here您可以找到有关贷款模式的更深入的解释。