所以我刚开始使用Scala并使用以下代码创建一个名为out
的伪数据的IndexedSeq。虚拟数据由20000个元组组成,每个元组包含36个字符的唯一标识符和1000个浮点数列表。
import scala.util.Random
def uuid = java.util.UUID.randomUUID.toString
def generateRandomList(size: Int): List[Float] = {
List.fill(size)(Random.nextFloat)
}
val numDimensions = 1000
val numberToWrite = 20000
val out = for ( i <- 1 to numberToWrite) yield {
val randomList = generateRandomList(numDimensions)
(uuid, randomList) // trying tuples insread
}
但是当我运行最后一个语句(只是通过复制并粘贴到Scala shell中)时,我收到以下错误:
java.lang.OutOfMemoryError: GC overhead limit exceeded
at java.lang.Float.valueOf(Float.java:433)
at scala.runtime.BoxesRunTime.boxToFloat(BoxesRunTime.java:73)
at $anonfun$generateRandomArray$1.apply(<console>:14)
at scala.collection.generic.GenTraversableFactory.fill(GenTraversableFactory.scala:90)
at .generateRandomArray(<console>:14)
at $anonfun$1.apply(<console>:17)
at $anonfun$1.apply(<console>:16)
at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:234)
at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:234)
at scala.collection.immutable.Range.foreach(Range.scala:160)
at scala.collection.TraversableLike$class.map(TraversableLike.scala:234)
at scala.collection.AbstractTraversable.map(Traversable.scala:104)
... 20 elided
这被解释为当我的大部分时间用于垃圾收集(GC)时发生的Java异常[1]。
根据[2],一个36字符串应该占用大约112字节。 Float需要4个字节。我的内部列表中有1000个,所以总共大约有4000个字节。因此,忽略列表和元组开销,然后我的out
IndexedSeq的每个元素将大约为~4200字节。所以拥有20000意味着总共~84e6字节。
考虑到这一点后,我运行了这个(取自[3]):
scala> val heapSize = Runtime.getRuntime().totalMemory(); // Get current size of heap in bytes
heapSize: Long = 212860928
scala> val heapMaxSize = Runtime.getRuntime().maxMemory(); // Get maximum size of heap in bytes. The heap cannot grow beyond this size.// Any attempt will result in an OutOfMemoryException.
heapMaxSize: Long = 239075328
scala> val heapFreeSize = Runtime.getRuntime().freeMemory(); // Get amount of free memory within the heap in bytes. This size will increase // after garbage collection and decrease as new objects are created.
heapFreeSize: Long = 152842176
虽然我认为我的最大堆大小似乎大于我认为需要的大量内存,但我尝试通过./scala -J-Xmx2g
增加堆大小([4])。虽然这解决了我的问题但最好知道是否有更好的方法来创建这个随机数据,避免我不得不增加JVM可用的内存?
因此,我有这三个问题,如果有人能回答,我将不胜感激:
什么时候在Scala中发生垃圾收集,特别是Scala shell?在上面的命令中,可以收集什么,为什么要调用GC(对不起,第二部分可能表明我对GC缺乏了解)?
我粗略计算的内存量是近似有效的(确定我预计列表和元组会有更多的开销,但假设相对不那么多)?如果是这样,当我的最大堆大小(239e6字节)应该覆盖这个时,为什么我的内存不足?如果不是我使用的额外记忆?
有没有更好的方法为此创建随机数据?对于上下文,我试图创建一些虚拟数据,我可以并行化为Spark(使用sc.parallelize),然后玩。 (所以当我在Spark中尝试它时让它工作我通过在我的spark conf而不是上面的spark.driver.memory 2g
命令中设置-J-Xmx2g
来增加驱动程序内存。
感谢您的帮助!
答案 0 :(得分:0)
回答REPL特定部分:
https://issues.scala-lang.org/browse/SI-4331
进行大量分配的人通常更喜欢Array
和Buffer
。
请注意List
中的开销,包括装箱原始值。
JVM堆在池中管理,您可以相对于彼此进行大小调整。但总的来说:
scala> var x = new Array[Byte](20000000 * 4)
x: Array[Byte] = Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ...
scala> x = null
x: Array[Byte] = null
scala> x = new Array[Byte](20000000 * 4)
x: Array[Byte] = [B@475530b9
scala> x = null
x: Array[Byte] = null
scala> x = new Array[Byte](20000000 * 4)
java.lang.OutOfMemoryError: Java heap space
... 32 elided