在spark的RDD中的transform操作算子中,总会调用sc.clean操作。当Scala构造一个闭包时,它确定闭包将使用哪些外部变量,并将它们的引用存储在闭包对象中。这允许封闭工作正常,即使它从不同的范围被调用时也是如此。
Scala-2.10-x以下的版本有时在捕捉太多外部变量方面犯了错误(参见SI-1419)。这在大多数情况下是无害的,因为额外捕获的变量根本不会被使用(尽管这会阻止它们获得GC'd)。但是它给Spark带来了一个问题,它必须通过网络发送闭包,以便它们可以在从属设备上运行。当闭包含不必要的引用时,会浪费网络带宽。更重要的是,某些引用可能指向不可序列化的对象,并且Spark将无法序列化闭包。
为了解决Scala中的这个bug,ClosureCleaner在运行时遍历对象并修剪不必要的引用。由于它在运行时执行此操作,因此它可能比Scala编译器更精确。然后Spark可以安全地序列化已清理的闭包