简体   繁体   中英

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:

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

As a quick-and-dirty solution I have created 2 separate tasks, compiling portions of the project in each. 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?

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

Fix 1: refactor the class

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

I think Kieron has one solution when he mentions the -Xss argument. javac takes a number of non-standard arguments that will vary between versions and compiler vendors.

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. You can increase the stack size for this compiler to 10Mb with this command:

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.

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

<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

Does this happen when you run the javac command from the command line? You might want to try the fork attribute.

Try adding some variation of these attributes to the Ant javac task line:

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

[Edit]: Added link -- the javac task page would seem to suggest that the parameters above require that you do also set fork="true" .

That's quite odd, 100 classes really isn't that many. 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?

One possible workaround is to simply increase the size of the stack using the -Xss argument to the JVM; either to the JVM running ant or by setting fork="true" and a <compilerarg> on the <javac> task. Actually now that I think of it, does the problem go away just putting in the 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). 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. 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. 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.

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? I think I'll post that question.

For those interested:

  • Windows XP SP2
  • SUN's JDK 1.4.2_17
  • Ant 1.7.0

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

ANT_OPTS=-Xss10M ant

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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