【问题标题】:Why does sbt compile fail with StackOverflowError?为什么 sbt 编译失败并出现 StackOverflowError?
【发布时间】:2016-03-22 23:36:43
【问题描述】:

我正在从事一个已经存在了几年但对我来说是新的 Scala 项目。我的任务是将它从 Scala 2.9.3 升级到 2.11.7,以及它的依赖项。我已经克服了错误和警告,但我无法让项目在 SBT 中成功编译。我总是在几乎同一个地方得到一个 StackOverflowError 。 stacktrace 看起来是这样的,但是细节会随着 Xss 设置而变化(目前是 4M,但尝试过高达 24M):

java.lang.StackOverflowError
at scala.tools.nsc.transform.Erasure$Eraser.typed1(Erasure.scala:698)
at scala.tools.nsc.typechecker.Typers$Typer.runTyper$1(Typers.scala:5395)
at scala.tools.nsc.typechecker.Typers$Typer.scala$tools$nsc$typechecker$Typers$Typer$$typedInternal(Typers.scala:5422)
at scala.tools.nsc.typechecker.Typers$Typer.body$2(Typers.scala:5369)
at scala.tools.nsc.typechecker.Typers$Typer.typed(Typers.scala:5373)
at scala.tools.nsc.typechecker.Typers$Typer.typedQualifier(Typers.scala:5471)
at scala.tools.nsc.typechecker.Typers$Typer.typedQualifier(Typers.scala:5479)
at scala.tools.nsc.transform.Erasure$Eraser.adaptMember(Erasure.scala:644)
at scala.tools.nsc.transform.Erasure$Eraser.typed1(Erasure.scala:698)
at scala.tools.nsc.typechecker.Typers$Typer.runTyper$1(Typers.scala:5395)
at scala.tools.nsc.typechecker.Typers$Typer.scala$tools$nsc$typechecker$Typers$Typer$$typedInternal(Typers.scala:5422)

SBT_OPTS 如下所示:

-Xmx2G -Xss4M -XX:+UseConcMarkSweepGC -XX:+CMSClassUnloadingEnabled

我可以在 Intellij 中成功“制作”该项目,其他人可以从 GitHub 中提取我的更改并在 sbt 中编译该项目,因此问题似乎是我的机器本地问题(最近的四核 Macbook Pro 具有 16GB RAM )。其他 Scala/sbt 项目在这台机器上为我成功编译。

以下是其他相关细节:

Scala version: 2.11.7
Java version: java version "1.8.0_66" (build 1.8.0_66-b17)
sbt version: 0.13.7 (have also tried 0.13.9)

我已经完全重建了 ivy2 缓存并清除了 lib_managed 目录。 scala-compiler.jar 的版本与在至少一台可以成功“sbt 编译”代码的机器上使用的版本相同。我重新安装了 sbt(通过 brew remove sbt,手动删除 ~/.sbt 目录,然后 brew install sbt)。

我没有尝试在错误发生时隔离正在编译的源代码行。我假设在某处寻找配置问题或依赖冲突会更有效率。

我们将不胜感激任何有关进一步故障排除的建议。

[已添加...] 补充一点可能会有所帮助,作为实验,我从https://github.com/scala/scala 下载了 Scala 语言源代码,并在尝试sbt compile 时遇到了以下非常相似的错误:

java.lang.StackOverflowError
at scala.tools.nsc.transform.ExplicitOuter$OuterPathTransformer.outerValue(ExplicitOuter.scala:229)
at scala.tools.nsc.transform.ExplicitOuter$ExplicitOuterTransformer.transform(ExplicitOuter.scala:441)
at scala.tools.nsc.transform.ExplicitOuter$ExplicitOuterTransformer.transform(ExplicitOuter.scala:352)
at scala.reflect.internal.Trees$class.itransform(Trees.scala:1345)
at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
at scala.reflect.api.Trees$Transformer.transform(Trees.scala:2555)
at scala.tools.nsc.transform.TypingTransformers$TypingTransformer.transform(TypingTransformers.scala:44)
at scala.tools.nsc.transform.ExplicitOuter$OuterPathTransformer.scala$reflect$internal$Trees$UnderConstructionTransformer$$super$transform(ExplicitOuter.scala:219)
at scala.reflect.internal.Trees$UnderConstructionTransformer$class.transform(Trees.scala:1693)
at scala.tools.nsc.transform.ExplicitOuter$OuterPathTransformer.transform(ExplicitOuter.scala:291)
at scala.tools.nsc.transform.ExplicitOuter$ExplicitOuterTransformer.transform(ExplicitOuter.scala:459)
at scala.tools.nsc.transform.ExplicitOuter$ExplicitOuterTransformer.transform(ExplicitOuter.scala:352)
at scala.reflect.internal.Trees$class.itransform(Trees.scala:1347)
at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
at scala.reflect.internal.SymbolTable.itransform(SymbolTable.scala:16)
at scala.reflect.api.Trees$Transformer.transform(Trees.scala:2555)

这里有一些有趣的东西。从this post 我发现了关于使用 -d 标志启动 sbt 以获取调试信息。得到以下输出:

Kevins-MacBook-Pro:scala kdoherty$ sbt -d
[process_args] java_version = '1.8.0_66'
# Executing command line:
java
-Xmx2G
-Xss4M
-XX:+UseConcMarkSweepGC
-XX:+CMSClassUnloadingEnabled
-Xmx384m
-Xss512k
-XX:+UseCompressedOops
-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005
-jar
/usr/local/Cellar/sbt/0.13.9/libexec/sbt-launch.jar

所以某处我的 SBT_OPTS 设置被覆盖(默认情况下,我猜)。现在我需要找到这些默认值的来源。

【问题讨论】:

  • 当你说你有相同版本的 scala-compiler.jar 和另一台可以编译它的计算机,你的意思是scalac -version 在两台计算机上返回相同的东西,或者两台计算机都有2.11.7在.sbt构建文件中定义?
  • @soong:两者都在 build.sbt 文件中指定了 2.11.7。
  • @KevinDoherty 你是否知道这台计算机上安装的 java 版本,以及它的所有 JVM 设置是什么?
  • @soong 我的另一台 Mac(13 英寸 MBP)将成功编译项目,它使用的是 Java 1.8.0-b132。没有使用特殊的 JVM 设置,只使用默认设置。
  • 它们看起来并没有被覆盖,而是被复制了! (我看到两个内存属性都被列出了两次,但值不同)

标签: scala sbt


【解决方案1】:

我想通了。一旦我知道 -d 标志会告诉我 SBT 实际使用的设置,我就会看到我的 SBT_OPTS 环境变量中的值被其他较低的设置所破坏。那些是从哪里来的?从我的 JAVA_OPTS 环境变量!我应该早点注意到它们,但现在我知道我可以保留这些 Java 选项,并通过将 SBT 特定设置添加到我的 /usr/local/etc/sbtopts 文件来覆盖 它们,使用

有点尴尬的格式
-J-Xmx2G
-J-Xss2M 

使用显示的值,我能够在我的项目上成功运行 sbt compile

我希望有人觉得这很有用。

【讨论】:

  • 如果我运行这个:sbt -Pyarn -pHadoop 2.7 assembly -J-Xss2M 我得到:Java HotSpot(TM) Client VM warning: ignoring option MaxPermSize=256m; 8.0 中删除了支持 - 有什么想法吗?
  • 升级 sbt,警告消失。
  • MaxPermSize 在 java 8 中被替换为 -XX:MaxMetaspaceSize
  • 如果有一个可以在 sbt 项目中运行的解决方案,那就太好了,因此可以在任何尝试构建的东西上运行
  • sbt -d 参数对我不起作用我得到一个“- 命令已弃用以支持onFailure,并将在 0.14.0 中删除”。也就是说,“sbt show scalacOptions”正在为我显示正确的内存设置。我的问题是编译器仍然以某种方式忽略/不尊重这些值。
【解决方案2】:

我发现我的 sbt 安装的 bin/sbt 文件中的 SBT_OPT 设置影响了我的项目 build.sbt 中设置的内存值

将此文件中现有的 -Xss 值从 1M 更新到 8M 将 Scalac 堆栈的内存大小提高到我在 sbt 调用的编译器中停止获取 StackOverflow 异常的程度。这似乎很奇怪,因为 sbt 记录的在编译器中设置堆栈大小的方法是使用 -J-Xss 设置。

Sbt 似乎实际上并不能让您设置编译器的堆栈内存。虽然 build.sbt 接受以下配置作为有效设置,但它似乎并未在编译器中应用该值:

ThisBuild ++= Seq(-J-Xss8M) 中的scalacOptions

我怀疑这是一个错误或未实现的功能

【讨论】:

    【解决方案3】:

    我无法通过提供的答案来解决这个问题。 build.sbt 设置和 sbtopts 文件都未能为我解决此错误。我必须做的是使用-mem 标志运行sbt,例如:

    sbt -mem 2048 compile
    

    现在我的项目已经建成。如果使用 IntelliJ,您也可以转到

    Preferences > Build, Execution, Deployment > Build Tools > sbt 
    

    并将Maximum heap size, MB 设置为您需要的任何目标。

    【讨论】:

      【解决方案4】:

      添加到 /usr/local/etc/sbtopts 的底部

      -J-Xmx4G 
      -J-Xss4M
      

      一切就绪。

      【讨论】:

        【解决方案5】:

        我刚刚在 Intellij sbt 属性中添加了 -Xss,问题就解决了。

        Intellij SBT properties

        【讨论】:

          【解决方案6】:

          sbt -h 输出的相关部分:

            # jvm options and output control
            JAVA_OPTS          environment variable, if unset uses ""
            .jvmopts           if this file exists in the current directory, its contents
                               are appended to JAVA_OPTS
            SBT_OPTS           environment variable, if unset uses ""
            .sbtopts           if this file exists in the current directory, its contents
                               are prepended to the runner args
          

          因此,就我而言,我通过创建带有内容的文件 .sbtopts 解决了这个问题

          -J-Xmx4G 
          -J-Xss4M
          

          在项目目录中。

          注意:运行sbt -d 会显示已使用的设置,例如:

          $ sbt -d
          [addSbt] arg = '-debug'
          [process_args] java_version = '8'
          # Executing command line:
          java
          -Xms1024m
          -XX:ReservedCodeCacheSize=128m
          -XX:MaxMetaspaceSize=256m
          -Xmx2G
          -Xss2M
          -jar
          /path/to/sbt-launch.jar
          -debug
          

          【讨论】:

            【解决方案7】:

            已经有多个正确答案。但对我有用的是下面,

            // Created and Added a File: .jvmopts in the Project Root Folder with below Parameters.
            -Xms3022m
            -Xmx4048m
            -Xss124m
            -XX:MaxPermSize=4048m
            -XX:MaxMetaspaceSize=512m
            -XX:+CMSClassUnloadingEnabled
            -XX:ReservedCodeCacheSize=128m
            

            【讨论】:

            • 为什么会有两次 MaxMetaspaceSize?
            【解决方案8】:

            我最近也遇到了这个问题,我通过sbt 1.3.13 发现了一个可行的解决方案。

            1. 在项目根目录下创建.sbtopts文件
            2. -J-Xss100M(或您认为合适的任何线程堆栈大小)添加到.sbtopts 文件中

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2015-01-27
              • 1970-01-01
              • 2016-08-16
              • 2021-12-22
              • 1970-01-01
              • 1970-01-01
              • 2013-05-14
              相关资源
              最近更新 更多