Using Ant tasks that create subprojects such as <antcall>
and <ant>
may cause build failures when invoked repeatedly due to one of the following errors:
- java.lang.OutOfMemoryError: PermGen space
- java.lang.OutOfMemoryError: Java heap space
The error only occurs when one of the tasks being called is defined using <typedef>
or <taskdef>
and does not appear when using tasks bundled with Ant such as <javadoc>
.
Is there a way to avoid the OutOfMemoryError
without increasing the
maximum Java heap size? Although increasing the heap size works for a
while, the problem still resurfaces if more memory intensive tasks are added.
The following example task and associated build.xml
file cause an
OutOfMemoryError
on my Linux box with the Java heap set to 10 MB (for
testing). The Ant task constructs a memory-hungry object (in this case a Guice
injector for a Closure Template Soy Module), which is then repeatedly called
using <antcall>
.
CreateGuiceInjectorTask.java
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.template.soy.SoyModule;
import org.apache.tools.ant.Task;
/** Custom Ant task that constructs a Guice injector. */
public final class CreateGuiceInjectorTask extends Task {
private Injector injector;
public CreateGuiceInjectorTask() {
injector = Guice.createInjector(new SoyModule());
}
public void execute() {
System.out.println("Constructed Guice injector...");
}
}
build.xml
<?xml version="1.0" encoding="UTF-8"?>
<project name="out-of-memory-test" basedir=".">
<property name="build.dir" location="${basedir}/build" />
<property name="CreateGuiceInjectorTask.jar"
location="${build.dir}/CreateGuiceInjectorTask.jar" />
<taskdef name="create-injector"
classname="CreateGuiceInjectorTask"
classpath="${CreateGuiceInjectorTask.jar}" />
<target name="call-create-injector">
<create-injector />
</target>
<target name="test"
description="Create multiple injectors until out of memory">
<antcall target="call-create-injector" />
<antcall target="call-create-injector" />
<antcall target="call-create-injector" />
<antcall target="call-create-injector" />
<antcall target="call-create-injector" />
<antcall target="call-create-injector" />
<antcall target="call-create-injector" />
<antcall target="call-create-injector" />
<antcall target="call-create-injector" />
<antcall target="call-create-injector" />
<antcall target="call-create-injector" />
<antcall target="call-create-injector" />
<antcall target="call-create-injector" />
</target>
</project>
Test Output:
$ ant test
test:
call-create-injector:
[create-injector] Constructed Guice injector...
call-create-injector:
[create-injector] Constructed Guice injector...
...
call-create-injector:
BUILD FAILED
Could not create type create-injector due to java.lang.OutOfMemoryError: Java heap space