【问题标题】:Why does a large array constructor call break the Scala compiler?为什么大型数组构造函数调用会破坏 Scala 编译器?
【发布时间】:2015-10-12 20:13:42
【问题描述】:

我正在为一份工作做一些图像处理,并且正在使用 Im4Java 编写脚本。为了编写一些单元案例,我决定将本地图像存储为代码中的字节数组。我抓了一张简单的测试图片

然后将其转换为字节数组,如下所示:

import java.nio.file.{Paths, Files}
import java.nio.charset.StandardCharsets
val stuff =scala.io.Source.fromFile(fileName)(scala.io.Codec.ISO8859).map(_.toByte).toArray
Files.write(Paths.get("tmp.txt"), stuff.mkString(",").getBytes(StandardCharsets.UTF_8))

然后将这些字节放入 Array[Byte] 应用构造函数中:

class testCase() {
    val smallFile = Array[Byte](-1,-40,-1, …) // 9816 arguments to the constructor passed here
}

当我尝试编译它时(请参阅this gist 中的完整 scala 文件),我惊讶地发现它破坏了编译器的打字机!我得到以下堆栈跟踪(我已经截断了一点):

[error] uncaught exception during compilation: java.lang.StackOverflowError
java.lang.StackOverflowError
at scala.reflect.internal.Symbols$Symbol.info(Symbols.scala:1241)
at scala.reflect.internal.Symbols$Symbol.baseTypeSeqLength$1(Symbols.scala:1628)
at scala.reflect.internal.Symbols$Symbol.isLess(Symbols.scala:1631)
at scala.reflect.internal.Types$Type.baseTypeIndex(Types.scala:992)
at scala.reflect.internal.Types$CompoundType.baseType(Types.scala:1655)
at scala.reflect.internal.Types$ClassTypeRef$class.baseType(Types.scala:2186)
at scala.reflect.internal.Types$TypeRef$$anon$6.baseType(Types.scala:2544)
at scala.reflect.internal.Types$class.firstTry$1(Types.scala:6064)
at scala.reflect.internal.Types$class.isSubType2(Types.scala:6228)
at scala.reflect.internal.Types$class.isSubType(Types.scala:5837)
at scala.reflect.internal.SymbolTable.isSubType(SymbolTable.scala:13)
at scala.reflect.internal.Types$class.fourthTry$1(Types.scala:6223)
at scala.reflect.internal.Types$class.thirdTryRef$1(Types.scala:6123)
at scala.reflect.internal.Types$class.thirdTry$1(Types.scala:6145)
at scala.reflect.internal.Types$class.secondTry$1(Types.scala:6109)
at scala.reflect.internal.Types$class.firstTry$1(Types.scala:6070)
at scala.reflect.internal.Types$class.isSubType2(Types.scala:6228)
at scala.reflect.internal.Types$class.isSubType(Types.scala:5837)
at scala.reflect.internal.SymbolTable.isSubType(SymbolTable.scala:13)
at scala.reflect.internal.Types$Type.$less$colon$less(Types.scala:872)
at scala.tools.nsc.typechecker.Typers$Typer.adapt(Typers.scala:1091)
at scala.tools.nsc.typechecker.Typers$Typer.typed(Typers.scala:5660)
at scala.tools.nsc.typechecker.Typers$Typer.typedArg(Typers.scala:3042)
at scala.tools.nsc.typechecker.Typers$Typer.loop$1(Typers.scala:3069)
at scala.tools.nsc.typechecker.Typers$Typer.loop$1(Typers.scala:3071)
at scala.tools.nsc.typechecker.Typers$Typer.loop$1(Typers.scala:3071)
at scala.tools.nsc.typechecker.Typers$Typer.loop$1(Typers.scala:3071)
at scala.tools.nsc.typechecker.Typers$Typer.loop$1(Typers.scala:3071)
at scala.tools.nsc.typechecker.Typers$Typer.loop$1(Typers.scala:3071)
(etc as this is where the stackoverflow happens)

我正在使用 Scala 2.10.5 编译器和 java jdk1.7.0_79

我可能会只使用较小的图像或其他东西来解决我的问题,但我想知道编译器为什么这样做以及是否可以修复?

【问题讨论】:

  • 通常,图像本身不会是问题,因为编译器不会在编译时知道它。
  • 我怀疑它与实际图像有关,因为在编译时会抛出错误。能否提供完整版代码(不清楚fileNameFilesPaths是如何定义的)?
  • @om-nom-nom 查看问题中链接的 gist 文件。
  • @Clashsoft 图片没有实际问题。我只是提供了代码,以便有人可以以相同的方式重现我在 gist 文件中使用的字节数组。
  • 也许你达到了 JVM 的“每个方法 64K 字节码”的限制?或者,好吧,您向该构造函数传递了超过 9000 个参数;一些消息来源似乎说有 255 个限制。

标签: arrays scala compiler-errors


【解决方案1】:

好吧,我试图重现您的问题,并且较新的 scalac (2.11.7) 有更好的错误消息(希望它能解决问题):

» scalac Arrays.scala
Arrays.scala:1: error: Could not write class testCase because it exceeds JVM code size limits. Method <init>'s code too large!
class testCase()  {
      ^
one error found

所以看起来,就像 @Marius noted in comments,你达到了 JVM 施加的“每个方法 64K 字节码”的限制。

【讨论】:

  • 所以它看起来像是一个答案,什么东西可以有多大取决于那些 JVM 设置?看起来有些限制在这个问题中被引用:stackoverflow.com/questions/17422480/…
  • 谢谢@om-nom-nom 这回答了这个问题,但是为了让遇到这个问题的其他人清楚地回答,您能否编辑您的答案以明确指出这是一个 JVM 代码大小限制以及显示来自编译器的错误?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-14
  • 2020-11-25
  • 2020-02-29
  • 1970-01-01
  • 1970-01-01
  • 2013-02-03
相关资源
最近更新 更多