简体   繁体   English

蚂蚁的<javac>任务抛出 StackOverflowException

[英]Ant's <javac> tasks throws StackOverflowException

I'm trying to compile over 100 java classes from different packages from a clean directory (no incremental compiles) using the following ant tasks:我正在尝试使用以下 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>

However, the first time I run the compile task I always get a StackOverflowException.然而,我第一次运行编译任务时总是得到一个 StackOverflowException。 If I run the task again the compiler does an incremental build and everything works fine.如果我再次运行该任务,编译器会进行增量构建,并且一切正常。 This is undesirable since we are using CruiseControl to do an automatic daily build and this is causing false build failures.这是不可取的,因为我们使用CruiseControl进行每日自动构建,这会导致错误的构建失败。

As a quick-and-dirty solution I have created 2 separate tasks, compiling portions of the project in each.作为一个快速而肮脏的解决方案,我创建了 2 个单独的任务,在每个任务中编译项目的一部分。 I really don't think this solution will hold as more classes are added in the future, and I don't want to be adding new compile tasks every time we hit the "compile limit".我真的不认为这个解决方案会随着未来添加更多类而成立,而且我不想每次达到“编译限制”时都添加新的编译任务。

It will be nice to know;很高兴知道; what can cause or causes a StackOverflowError during compilation of Java code?在 Java 代码编译期间,什么会导致或导致 StackOverflowError?

It is probable that evaluating the long expression in your java file consumes lots of memory and because this is being done in conjunction with the compilation of other classes, the VM just runs out of stack space.评估您的 java 文件中的长表达式很可能会消耗大量内存,并且因为这是与其他类的编译一起完成的,所以 VM 会耗尽堆栈空间。 Your generated class is perhaps pushing the legal limits for its contents.您生成的类可能正在推动其内容的法律限制。 See chapter 4.10 Limitations of the Java Virtual Machine in The Java Virtual Machine Specification, Second Edition .请参阅The Java Virtual Machine Specification, Second Edition 中的4.10Java 虚拟机的限制

Fix 1: refactor the class修复 1:重构类

Since your class is being generated, this might not be an option.由于您的类正在生成,因此这可能不是一个选项。 Still, it is worth looking at the options your class generation tool offers to see if it can produce something less troublesome.尽管如此,还是值得看看你的类生成工具提供的选项,看看它是否可以产生不那么麻烦的东西。

Fix 2: increase the stack size修复 2:增加堆栈大小

I think Kieron has one solution when he mentions the -Xss argument.我认为Kieron在提到 -Xss 参数时有一个解决方案。 javac takes a number of non-standard arguments that will vary between versions and compiler vendors. javac采用许多非标准参数,这些参数会因版本和编译器供应商而异。

My compiler:我的编译器:

$ javac -version
javac 1.6.0_05

To list all the options for it, I'd use these commands:要列出它的所有选项,我将使用以下命令:

javac -help
javac -X
javac -J-X

I think the stack limit for javac is 512Kb by default.认为javac 的堆栈限制默认为 512Kb。 You can increase the stack size for this compiler to 10Mb with this command:您可以使用以下命令将此编译器的堆栈大小增加到 10Mb:

javac -J-Xss10M Foo.java

You might be able to pass this in an Ant file with a compilerarg element nested in your javac task.您可能能够在一个 Ant 文件中传递它,并在您的javac任务中嵌套一个compilerarg元素。

<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>

from the comment above is incorrect.上面评论是不正确的。 You need a space between the -J and -X, like so: -J 和 -X 之间需要一个空格,如下所示:

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

to avoid the following error:避免以下错误:

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

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

Does this happen when you run the javac command from the command line?从命令行运行 javac 命令时会发生这种情况吗? You might want to try the fork attribute.您可能想尝试fork属性。

Try adding some variation of these attributes to the Ant javac task line:尝试将这些属性的一些变体添加到Ant javac任务行:

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

You can also try fork="true" , not sure if this allows you to set values for stack and heap (aka -Xm1024), but it may help (if it would work from the command line, but not in Ant).您也可以尝试fork="true" ,不确定这是否允许您为堆栈和堆(又名 -Xm1024)设置值,但它可能会有所帮助(如果它可以从命令行运行,但不能在 Ant 中运行)。

[Edit]: Added link -- the javac task page would seem to suggest that the parameters above require that you do also set fork="true" . [编辑]:添加了链接javac任务页面似乎建议上述参数要求您还设置fork="true"

That's quite odd, 100 classes really isn't that many.这很奇怪,100 个班级真的不多。 What is the compiler doing when the stack overflows?堆栈溢出时编译器在做什么? Is there a useful stack trace generated?是否生成了有用的堆栈跟踪? What happens if you run javac directly on the command line instead of thorugh ant?如果直接在命令行上运行javac而不是通过 ant 会发生什么?

One possible workaround is to simply increase the size of the stack using the -Xss argument to the JVM;一种可能的解决方法是使用 JVM 的-Xss参数简单地增加堆栈的大小; either to the JVM running ant or by setting fork="true" and a <compilerarg> on the <javac> task.要么到运行ant的 JVM,要么通过在<javac>任务上设置fork="true"和一个<compilerarg> Actually now that I think of it, does the problem go away just putting in the fork="true" ?实际上,现在我想起来了,只要输入fork="true"问题就会消失吗?

Here is what I found.这是我发现的。 After posting my question I went on and modified the compile task with the attributes fork="true" , memoryinitialsize="256m" and memorymaximumsize="1024m" (a found today that this was suggested by Kieron and jmanning2k, thanks for your time).发布我的问题后,我继续使用属性fork="true"memoryinitialsize="256m"memorymaximumsize="1024m"修改编译任务(今天发现这是 Kieron 和 jmanning2k 建议的,感谢您的时间) . This didn't solve the problem nonetheless.尽管如此,这并没有解决问题。

I decided to start removing classes from the source tree to see if a could pinpoint the problem.我决定开始从源树中删除类,看看是否可以查明问题。 Turns out we had a Web Service client class for Axis 1.4 that was auto-generated from a WSDL file.结果我们有一个用于Axis 1.4的 Web 服务客户端类,它是从 WSDL 文件自动生成的。 Now, this class is a monster (as in Frankenstein), it has 167 field members (all of them of type String), 167 getter/setter pairs (1 for each field), a constructor that receives all 167 fields as parameters, an equals method that compares all 167 fields in a strange way.现在,这个类是一个怪物(就像在 Frankenstein 中一样),它有 167 个字段成员(它们都是 String 类型),167 个 getter/setter 对(每个字段 1 个),一个接收所有 167 个字段作为参数的构造函数,一个以一种奇怪的方式比较所有 167 个字段的 equals 方法。 For each field the comparison goes like this:对于每个字段,比较如下:

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

The result of this comparison is "anded" (&&) with the result of the comparison of the next field, and so on.此比较的结果与下一个字段的比较结果“与”(&&),依此类推。 The class goes on with a hashCode method that also uses all fields, some custom XML serialization methods and a method that returns a Axis-specific metadata object that describes the class and that also uses all field members.该类继续使用 hashCode 方法,该方法也使用所有字段、一些自定义 XML 序列化方法和一个方法,该方法返回一个特定于 Axis 的元数据对象,该对象描述该类并且还使用所有字段成员。

This class is never modified, so I just put a compiled version in the application classpath and the project compiled without issues.这个类永远不会被修改,所以我只是在应用程序类路径中放了一个编译版本,项目编译没有问题。

Now, I know that removing this single source file solved the problem.现在,我知道删除这个单一的源文件解决了这个问题。 However, I have absolutely no idea as to why this particular class caused the problem.但是,我完全不知道为什么这个特定的类会导致这个问题。 It will be nice to know;很高兴知道; what can cause or causes a StackOverflowError during compilation of Java code?在 Java 代码编译期间,什么会导致或导致 StackOverflowError? I think I'll post that question.我想我会发布这个问题。

For those interested:对于那些有兴趣的人:

  • Windows XP SP2视窗 XP SP2
  • SUN's JDK 1.4.2_17 SUN 的 JDK 1.4.2_17
  • Ant 1.7.0蚂蚁 1.7.0

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

ANT_OPTS=-Xss10M ant

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM