Scala shell 中的垃圾收集
Posted
技术标签:
【中文标题】Scala shell 中的垃圾收集【英文标题】:Garbage collection in the Scala shell 【发布时间】:2016-11-11 04:11:57 【问题描述】:所以我刚刚开始使用 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) [1] 上时发生的 Java 异常。
根据 [2],一个 36 字符的字符串大约需要 112 个字节。浮点数占用 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
命令来增加驱动程序内存)。
感谢您的帮助!
链接
-
Error java.lang.OutOfMemoryError: GC overhead limit exceeded
How much memory does a string use in Java 8?
How to view the current heap size that an application is using?
Increase JVM heap size for Scala?
【问题讨论】:
+1 个很好的问题,背后有很多有用的研究;很难相信它没有被投票,而且它只有一个答案 【参考方案1】:回答 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
【讨论】:
在风格上更喜欢Array.ofDim[Byte](10)
和 Array.fill(10)(1: Byte)
。以上是关于Scala shell 中的垃圾收集的主要内容,如果未能解决你的问题,请参考以下文章