【问题标题】:Scala console: OutOfMemoryError: GC overhead limit exceededScala 控制台:OutOfMemoryError:超出 GC 开销限制
【发布时间】:2018-09-05 08:35:35
【问题描述】:

斯卡拉:

(1 to 100000000).toList.foldLeft(0)((acc, x) => acc + x)

灵药:

1..100000000 |> Enum.to_list |> List.foldl(0, fn x, acc -> x + acc end)

它们具有相同的功能。但是,JVM 只是抛出了 GC 异常,而 BEAM 可以安全地处理它。我只是好奇为什么JVM无法处理这种情况?是JVM的错还是Scala编译器的错? (我知道我可以使用 Stream 或 View 来处理这种情况)

【问题讨论】:

  • 也许您需要增加堆大小?没有“JVM 整体优于 BEAM”之类的东西,它们是橙色和苹果。
  • JVM 总体上优于 BEAM,但无法分配 100000000 和溢出整数的列表。哈哈。
  • “JVM 总体上优于 BEAM” 对此投了反对票。
  • 拥有相同的功能不等于拥有相同的实现。在这种情况下,您的 Scala 代码对toList 进行了不必要的调用,这是问题的原因。 Elixir 代码很可能以不同的方式实现,即使它在 JVM 上运行也可以避免问题。
  • 我对“JVM 总体上优于 BEAM”这一点有点矛盾,这几乎不是技术对话,我很想仅就这一点投票。然而,由于有一些关于 Laziness 和 Scala 的内容,这个问题并不完全缺乏价值。小心@chenyuandong 在技术工作中的价值判断。

标签: scala jvm erlang elixir beam


【解决方案1】:

我不知道 Elixir 是如何处理这个操作的,但是toList 将创建一个包含 100000000 个条目的真实 List 对象。如果您跳过该步骤,该操作在 Scala 中也将成功:

scala> (1 to 100000000).foldLeft(0)((acc,x) => acc + x)
res1: Int = 987459712

【讨论】:

  • 确实如此,因为 1 到 N 是懒惰的。结果是错误的(超出了Int类型的范围)。
  • 是的,但是为什么一个真正的 List 对象有 100000000 个 Boxed Integer 条目会爆炸 GC?这是某种问题。
  • 您可以使用BigInt修复整数溢出问题:(1 to 100000000).foldLeft(BigInt(0))((acc,x) => acc + x)
  • 对对对。这不是我问题的关键部分。
  • 从堆栈跟踪和错误消息猜测,可能是toList 方法不会立即分配结果列表,而是一次又一次地增加其大小。从而产生了如此多的垃圾,以至于虚拟机在 GC 中花费的时间最多,这会导致观察到的异常。
猜你喜欢
  • 2013-07-13
  • 2022-01-01
  • 1970-01-01
  • 2017-07-04
  • 1970-01-01
  • 2017-04-20
  • 2013-06-11
  • 2011-05-21
  • 1970-01-01
相关资源
最近更新 更多