6

我正在尝试使用以下 ant 任务从干净的目录(无增量编译)中编译来自不同包的 100 多个 java 类:

<target name="-main-src-depend">
    <depend srcdir="${src.dir}" 
            destdir="${bin.dir}" 
            cache="${cache.dir}"
            closure="true"/>
</target>   

<target name="compile" depends="-main-src-depend"
        description="Compiles the project.">

    <echo>Compiling</echo>

    <javac  target="${javac.target}"
            source="${javac.source}"
            debug="${javac.debug}"
            srcdir="${src.dir}"
            destdir="${bin.dir}">
        <classpath>
            <path refid="runtime.classpath"/>
            <path refid="compile.classpath"/>
        </classpath>
    </javac>
</target>

但是,第一次运行编译任务时,我总是得到一个 StackOverflowException。如果我再次运行该任务,编译器会进行增量构建并且一切正常。这是不可取的,因为我们使用CruiseControl进行自动每日构建,这会导致错误的构建失败。

作为一个快速和肮脏的解决方案,我创建了 2 个单独的任务,在每个任务中编译项目的一部分。我真的不认为这个解决方案会在将来添加更多类时成立,而且我不希望每次达到“编译限制”时都添加新的编译任务。

4

7 回答 7

5

很高兴知道;在编译 Java 代码期间,什么会导致或导致 StackOverflowError?

评估 java 文件中的长表达式可能会消耗大量内存,因为这是与其他类的编译一起完成的,VM 只是用完了堆栈空间。您生成的类可能正在推动其内容的法律限制。请参阅The Java Virtual Machine Specification, Second Edition中的第4.10章Java 虚拟机的限制。

修复 1:重构类

由于正在生成您的课程,因此这可能不是一个选项。尽管如此,还是值得看看你的类生成工具提供的选项,看看它是否能产生一些不那么麻烦的东西。

修复 2:增加堆栈大小

当Kieron提到 -Xss 参数时,我认为他有一个解决方案。javac采用许多非标准参数,这些参数会因版本和编译器供应商而异。

我的编译器:

$ javac -version
javac 1.6.0_05

要列出它的所有选项,我会使用以下命令:

javac -help
javac -X
javac -J-X

认为javac 的堆栈限制默认为 512Kb。您可以使用以下命令将此编译器的堆栈大小增加到 10Mb:

javac -J-Xss10M Foo.java

您可能可以在 Ant 文件中传递它,并在您的javac任务中嵌套一个compilerarg元素。

<javac srcdir="gen" destdir="gen-bin" debug="on" fork="true">
    <compilerarg value="-J-Xss10M" />
</javac>
于 2008-08-21T12:58:37.930 回答
3
  <javac srcdir="gen" destdir="gen-bin" debug="on" fork="true">
      <compilerarg value="-J-Xss10M" />
    </javac>

上面的评论是不正确的。-J 和 -X 之间需要一个空格,如下所示:

<javac srcdir="gen" destdir="gen-bin" debug="on" fork="true">
    <compilerarg value="-J -Xss10M" />
</javac>

以避免出现以下错误:

 [javac] 
[javac] The ' characters around the executable and arguments are
[javac] not part of the command.
[javac] Files to be compiled:

... [javac] javac:无效标志:-J-Xss1m [javac] 用法:javac

于 2009-06-25T04:50:34.720 回答
1

从命令行运行 javac 命令时会发生这种情况吗?您可能想尝试fork属性。

于 2008-08-19T21:04:42.723 回答
1

尝试将这些属性的一些变体添加到Antjavac任务行:

memoryinitialsize="256M" memorymaximumsize="1024M"

您也可以尝试fork="true",不确定这是否允许您设置堆栈和堆的值(又名 -Xm1024),但它可能会有所帮助(如果它可以从命令行工作,但不能在 Ant 中工作)。

[编辑]:添加链接 -javac任务页面似乎建议上述参数要求您也设置fork="true".

于 2008-08-19T21:05:28.010 回答
0

这很奇怪,100 个班真的没有那么多。堆栈溢出时编译器在做什么?是否生成了有用的堆栈跟踪?如果你javac直接在命令行上运行而不是通过 ant 会发生什么?

-Xss一种可能的解决方法是使用JVM的参数简单地增加堆栈的大小;要么给 JVM 运行,要么通过在任务上ant设置fork="true"和 a 。实际上,现在我想起来了,问题就解决了吗?<compilerarg><javac>fork="true"

于 2008-08-19T21:21:16.607 回答
0

这是我发现的。发布我的问题后,我继续使用属性修改了编译任务fork="true"memoryinitialsize="256m"并且memorymaximumsize="1024m"(今天发现这是 Kieron 和 jmanning2k 建议的,感谢您的时间)。然而这并没有解决问题。

我决定开始从源代码树中删除类,看看是否可以查明问题。原来我们有一个用于Axis 1.4的 Web 服务客户端类,它是从 WSDL 文件自动生成的。现在,这个类是一个怪物(就像在科学怪人中一样),它有 167 个字段成员(它们都是 String 类型),167 个 getter/setter 对(每个字段 1 个),一个接收所有 167 个字段作为参数的构造函数,一个equals 方法以一种奇怪的方式比较所有 167 个字段。对于每个字段,比较如下:

(this.A == null && other.getA() == null) || (this.A != null && this.A.equals(other.getA()))

此比较的结果与下一个字段的比较结果“与”(&&),依此类推。该类继续使用也使用所有字段的 hashCode 方法、一些自定义 XML 序列化方法和返回描述类并且还使用所有字段成员的 Axis 特定元数据对象的方法。

这个类永远不会被修改,所以我只是在应用程序类路径中放置了一个编译版本,并且项目编译没有问题。

现在,我知道删除这个单一的源文件解决了这个问题。但是,我完全不知道为什么这个特定的类会导致问题。很高兴知道;在编译 Java 代码期间,什么会导致或导致 StackOverflowError?我想我会发布这个问题。

对于那些感兴趣的人:

  • 视窗 XP SP2
  • SUN的JDK 1.4.2_17
  • 蚂蚁 1.7.0
于 2008-08-20T14:23:06.457 回答
0

其他一些答案提到了需要设置的修复,但另一种选择是通过设置环境变量fork="true"来增加 ant 创建的底层 JVM 的堆栈空间:ANT_OPTS

ANT_OPTS=-Xss10M ant
于 2021-04-05T19:02:30.063 回答