java - Ant taskdef - PermGen 空间用完

标签 java ant typedef out-of-memory taskdef

使用 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/

相关文章:

使用相同大小的缓冲区的 Java 复制流

java - 用于递归结构的json解析器

ant - 将 antcall 目标中定义的属性传递回调用目标

logging - 让 Ant 登录到文件以及屏幕/终端

grails - 在Grails构建目标中使用Hudson构建参数

c - 带有 typedef 的结构

c - 在嵌入式 C 代码中使用 typedef 结构

c++ - 结构和指针 C++

原始类型的 Java 迭代器

java - 通过 Java 发送邮件时出现异常