使用 Ant 任务创建子项目,例如 <antcall>
和 <ant>
由于以下错误之一,重复调用时可能会导致构建失败:
- java.lang.OutOfMemoryError: PermGen 空间
- java.lang.OutOfMemoryError: Java 堆空间
仅当调用的任务之一是使用 <typedef>
定义时才会发生错误或 <taskdef>
并且在使用与 Ant 捆绑在一起的任务时不会出现,例如 <javadoc>
.
有没有办法避免 OutOfMemoryError
不增加
最大 Java 堆大小?虽然增加堆大小适用于
同时,如果添加更多内存密集型任务,问题仍然会再次出现。
以下示例任务与build.xml
相关联文件导致
OutOfMemoryError
在我的 Linux 机器上,Java 堆设置为 10 MB(对于
测试)。 Ant 任务构造一个内存消耗大的对象(在本例中是一个 Guice
封闭模板大 bean 模块的注入(inject)器),然后重复调用
使用 <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>
测试输出:
$ 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
最佳答案
使用 Keith Gregory's方法描述here我能够解决内存问题,至少对于您发布的简单示例代码而言。
概括地说,问题是每次您通过 antcall
使用 taskdef 时,Ant 使用不同的类加载器,因此您会立即吃掉您的 permgen。要确认这一点,您可以修改您的类以打印类加载器哈希码 - 您会在每次迭代中看到它的不同。
解决方法是将您的 taskdef 打包为 antlib并使用 antlib 命名空间来加载它。结果是使用了 Ant 自己的类加载器。为此,您必须将该类放在 Ant 类路径中。
为了对此进行测试,我将您的测试类放入包命名空间(称为 memtest)中,进行编译,然后在包目录中添加一个 antlib.xml,如下所示:
<antlib>
<taskdef name="create-injector" classname="memtest.CreateGuiceInjectorTask" />
</antlib>
构建文件项目声明更改为
<project name="out-of-memory-test" basedir="." default="test" xmlns:mt="antlib:memtest">
和目标
<target name="call-create-injector">
<mt:create-injector />
</target>
为了测试,我将所有需要的东西都放在了 Ant 类路径中。它成功运行了许多 antcalls,并且类加载器哈希码的调试打印确认使用了预期的单个实例。
Ant documentation for the antlib namespace 中有一条注释上面写着“资源位于默认类路径中的要求可能会在 Ant 的 future 版本中删除”。根据实现方式的不同,变通办法将来可能会中断。
关于java - Ant taskdef - PermGen 空间用完,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10662614/