tags:

views:

2638

answers:

7

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

A: 

What is the full stacktrace of the StackOverflowException? What operating system, JDK, and Ant version are you using?

David Schlosnagle
A: 

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

McDowell
A: 

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 [ant javac task] page would seem to suggest that the parameters above require that you also set fork="true".

jmanning2k
A: 

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

Kieron
A: 

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
Elliot Vargas
+3  A: 

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>
McDowell
The last part of this answer will yield an Error from javac. Please see this answer: http://stackoverflow.com/questions/16935/ants-javac-tasks-throws-stackoverflowexception/1042236#1042236
npellow
Adding a space causes this error with Sun javac 1.6.0_05 on WinXP: "java.lang.NoClassDefFoundError: -Xss10M" ... I'm guessing this must be compiler-dependent.
McDowell
A: 
  <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

npellow