蚂蚁的任务抛出StackOverflowException

时间:2020-03-05 18:40:53  来源:igfitidea点击:

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

<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个单独的任务,并在每个任务中编译项目的各个部分。我真的不认为此解决方案会随着将来添加更多的类而保持不变,并且我不想每次我们达到"编译限制"时都添加新的编译任务。

解决方案

回答

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

回答

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

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

我们也可以尝试使用fork =" true",不确定是否允许我们设置堆栈和堆的值(aka -Xm1024),但这可能会有所帮助(如果它可以在命令行中运行,但在Ant中不行) 。

[编辑]:
添加了链接-javac任务页面似乎表明上述参数要求我们也设置fork =" true"

回答

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

一种可能的解决方法是使用JVM的-Xss参数来简单地增加堆栈的大小。或者运行ant的JVM,或者在<javac>任务上设置fork =" true"&lt;compilerarg>。实际上,现在我想到了,仅放入fork =" true"即可解决问题吗?

回答

这是我发现的。
发表我的问题后,我继续并使用属性fork =" true"memoryinitialsize =" 256m"memorymaximumsize =" 1024m"修改了编译任务(今天发现这是Kieron和jmanning2k建议的, 谢谢你的时间)。但这并不能解决问题。

我决定开始从源代码树中删除类,以查看是否可以查明问题。事实证明,我们有一个从WSDL文件自动生成的Axis 1.4的Web服务客户端类。现在,该类是一个怪物(就像在科学怪人中一样),它具有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?我想我将发布该问题。

对于那些感兴趣的人:

  • Windows XP SP2
  • SUN的JDK 1.4.2_17
  • 蚂蚁1.7.0

回答

It will be nice to know; what can
  cause or causes a StackOverflowError
  during compilation of Java code?

评估Java文件中的长表达式可能会消耗大量内存,并且由于这是与其他类的编译一起完成的,因此VM只会耗尽堆栈空间。我们生成的类可能正在推动其内容的法律限制。请参阅《 Java虚拟机规范,第二版》中的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

我们可能可以在带有嵌套在javac任务中的editorarg元素的Ant文件中传递它。

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

回答

<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