Spark RDDs在每个分区内有共享指针(和幻数200 ??)

时间:2014-11-22 16:35:12

标签: scala apache-spark rdd

我试图坚持一个火花RDD,其中每个分区的元素都共享一个大对象的访问权限。但是,此对象似乎多次存储在内存中。将我的问题减少到仅有200个元素的单个分区的玩具箱:

val nElements = 200
class Elem(val s:Array[Int])

val rdd = sc.parallelize(Seq(1)).mapPartitions( _ => {
    val sharedArray = Array.ofDim[Int](10000000) // Should require ~40MB
    (1 to nElements).toIterator.map(i => new Elem(sharedArray))
}).cache()

rdd.count() //force computation    

这会消耗预期的内存量,如日志中所示:

  

storage.MemoryStore:阻止rdd_1_0存储为内存中的值(估计大小为38.2 MB,空闲5.7 GB)

但是,200是这样的元素的最大数量。设置nElements=201会产生:

  

storage.MemoryStore:阻止rdd_1_0存储为内存中的值(估计大小为76.7 MB,空闲5.7 GB)

是什么原因引起的?这个神奇的数字200来自哪里,我该怎样才能增加它?


编辑澄清

向函数添加println表明它确实只调用一次。此外,运行:

rdd.map(_.s.hashCode).min == rdd.map(_.s.hashCode).max  // returns true

..揭示了所有10000000个元素确实指向同一个对象,因此数据结构本质上表现正确。当nExamples更大(例如20000)时会出现问题,因此它无法持久存在。

  

storage.MemoryStore:没有足够的空间来缓存内存中的rdd_1_0! (到目前为止计算为6.1 GB)

当我设置nExamples=500时,它成功地将rdd保留在内存中,说估计大小为1907.4 MB ,但我可以看到我的内存使用量的实际增加远远小于此值。< / p>

1 个答案:

答案 0 :(得分:0)

对于任何在未来遇到这种情况的人来说,我最终想出了一个超级黑客的解决方案(尽管我仍然乐于听到更好的解决方案)。而不是使用rdd.cache(),我定义:

def cached[T: ClassTag](rdd:RDD[T]) = {
    rdd.mapPartitions(p => 
        Iterator(p.toSeq)
    ).cache().mapPartitions(p =>
        p.next().toIterator
    )
}

以便cached(rdd)返回从缓存的&#39;生成的RDD。列表