小文本数据上的Spark OutOfMemory错误

时间:2014-06-24 19:22:58

标签: java scala apache-spark

我正在努力实现一种算法,并在本地节点上的Spark(Scala接口)中的中型数据上进行测试。我从非常简单的处理开始,我得到java.lang.OutOfMemoryError: Java heap space,即使我非常确定数据不够大,不能使这样的错误合理。这是最小的破解代码:

import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkContext, SparkConf}

val conf = new SparkConf()
  .setMaster("local[4]")
  .setAppName("AdultProcessing")
  .set("spark.executor.memory", "1g")
val sc = new SparkContext(conf)

val dataFile = "data/census/processed/census-income.data"
val censusData: RDD[String] = sc.textFile(dataFile, 4)
val censusDataPreprocessed = censusData.map { row =>
  val separators: Array[Char] = ":,".toCharArray
  row.split(separators)
}

val res = censusDataPreprocessed.collect()

我正在使用的数据是the classic census data,未压缩。这是100MB和几乎20万行。我的机器上的内存量应该足够了:

nietaki@xebab$ free -tm
             total       used       free     shared    buffers     cached
Mem:         15495      12565       2929          0        645       5608
-/+ buffers/cache:       6311       9183
Swap:         3858          0       3858
Total:       19354      12566       6788

对于每个虚拟节点,数据文件的块大小不超过30MB,我正在执行的唯一处理是将行字符串拆分为50个以下项目的数组。我无法相信这个操作应该耗尽内存。

在尝试调试情况时,我发现将节点数减少到1,或者将SparkContext.textFile()的{​​{3}}参数从4增加到8,例如可以解决这种情况,但它并没有让我更聪明。

我正在使用Spark 1.0.0和Scala 2.10.4。我是直接从sbt:sbt run -Xmx2g -Xms2g启动项目的。

1 个答案:

答案 0 :(得分:0)

JVM内存很耗力。 Spark在JVM上运行。

我建议您使用分析器检查堆,以找出记录使用的实际内存。在我的情况下,他们的大小是#34;在休息时#34;它们是原始类型和字符串的组合。

在你的情况下,字符串特别容易记忆。 ""(空字符串)长约40个字节 - 较长的字符串抵消了结构的成本。见[1]

将先前资源中的表应用于您的数据:

line: String = 73, Not in universe, 0, 0, High school graduate, 0, Not in universe, Widowed, Not in universe or children, Not in universe, White, All other, Female, Not in universe, Not in universe, Not in labor force, 0, 0, 0, Nonfiler, Not in universe, Not in universe, Other Rel 18+ ever marr not in subfamily, Other relative of householder, 1700.09, ?, ?, ?, Not in universe under 1 year old, ?, 0, Not in universe, United-States, United-States, United-States, Native- Born in the United States, 0, Not in universe, 2, 0, 95, - 50000.

line.size
Int = 523
def size(s:String) = s.size/4*8+40
line.split(",.").map(w=>size(w)).sum
Int = 2432

所以,多亏了所有这些小字符串,你的内存中的数据大小是休息时间的5倍。 尽管如此,该数据的200k行仍然占据了大约500MB。这可能表示您的执行程序以512MB的默认值运行。尝试设置' spark.executor.memory'为了更高的价值,还要考虑堆大小> 8Gb以便与Spark配合使用。