Ant的<javac>任务抛出StackOverflowException </javac>

时间:2008-08-19 20:53:53

标签: java ant

我正在尝试从一个干净的不同包中编译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进行自动每日构建,这会导致错误的构建失败。

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

7 个答案:

答案 0 :(得分:5)

  

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

评估java文件中的long表达式可能会消耗大量内存,并且因为这是与其他类的编译一起完成的,所以VM只是耗尽了堆栈空间。您生成的类可能会推动其内容的法律限制。请参阅4.10 Limitations of the Java Virtual Machine中的The Java Virtual Machine Specification, Second Edition一章。

修复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文件中传递此内容,其中 compilerarg 元素嵌套在 javac 任务中。

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

答案 1 :(得分:2)

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

不正确。你需要在-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

答案 2 :(得分:1)

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

答案 3 :(得分:1)

尝试将这些属性的一些变体添加到Ant javac task行:

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

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

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

答案 4 :(得分:0)

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

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

答案 5 :(得分: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()))

此比较的结果是“anded”(&amp;&amp;),其中包含下一个字段的比较结果,依此类推。该类继续使用hashCode方法,该方法还使用所有字段,一些自定义XML序列化方法以及返回描述该类并且还使用所有字段成员的特定于轴的元数据对象的方法。

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

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

对于那些感兴趣的人:

  • Windows XP SP2
  • SUN的JDK 1.4.2_17
  • Ant 1.7.0

答案 6 :(得分:0)

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

ANT_OPTS=-Xss10M ant