Ant 的 <javac> 任务抛出 StackOverflowException
题
我正在尝试使用以下蚂蚁任务从干净目录(无增量编译)中从不同软件包中编译100多个Java类:
<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>
但是,第一次运行编译任务时,我总是遇到 StackOverflowException。如果我再次运行该任务,编译器会进行增量构建,并且一切正常。这是不希望的,因为我们正在使用 巡航控制 进行自动每日构建,这会导致错误的构建失败。
作为一个快速而肮脏的解决方案,我创建了 2 个单独的任务,在每个任务中编译项目的部分内容。我真的不认为这个解决方案会持续下去,因为将来会添加更多的类,而且我不想每次达到“编译限制”时都添加新的编译任务。
解决方案
很高兴知道;在Java代码编辑期间,什么可能导致或导致stackoverflowerror?
计算 java 文件中的长表达式可能会消耗大量内存,并且因为这是与其他类的编译一起完成的,所以虚拟机会耗尽堆栈空间。您生成的类可能正在突破其内容的法律限制。参见章节 4.10 Java虚拟机的局限性 在 Java 虚拟机规范,第二版.
修复1:重构类
由于正在生成您的类,因此这可能不是一个选项。尽管如此,还是值得看看您的类生成工具提供的选项,看看它是否可以产生不那么麻烦的东西。
修复2:增加堆栈大小
我认为 基隆 当他提到 -Xss 参数时有一个解决方案。 javac 采用许多非标准参数,这些参数在版本和编译器供应商之间会有所不同。
我的编译器:
$ javac -version
javac 1.6.0_05
要列出它的所有选项,我将使用以下命令:
javac -help
javac -X
javac -J-X
我 思考 javac 的堆栈限制默认为 512Kb。您可以使用以下命令将此编译器的堆栈大小增加到 10Mb:
javac -J-Xss10M Foo.java
您也许可以将其传递到 Ant 文件中,并使用 编译器参数 元素嵌套在你的 javac 任务。
<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>
来自 上面评论 是不正确的。-J 和 -X 之间需要有一个空格,如下所示:
<javac srcdir="gen" destdir="gen-bin" debug="on" fork="true">
<compilerarg value="-J -Xss10M" />
</javac>
以避免出现以下错误:
[javac]
[javac] The ' characters around the executable and arguments are
[javac] not part of the command.
[javac] Files to be compiled:
...[javac] javac:无效标志:-j-XSS1M [JAVAC]用法:javac
尝试将这些属性的一些变体添加到 蚂蚁 javac
任务 线:
memoryinitialsize="256M" memorymaximumsize="1024M"
你也可以尝试 fork="true"
, ,不确定这是否允许您设置堆栈和堆的值(又名 -Xm1024),但它可能会有所帮助(如果它可以从命令行工作,但不能在 Ant 中工作)。
[编辑]:添加了链接—— javac
任务 页面似乎建议上面的参数要求您还设置 fork="true"
.
从命令行运行 javac 命令时是否会发生这种情况?您可能想尝试 叉 属性。
这很奇怪,100 个类实际上并不算多。当堆栈溢出时编译器在做什么?是否生成了有用的堆栈跟踪?如果你跑步会发生什么 javac
直接在命令行上而不是通过ant?
一种可能的解决方法是简单地使用以下命令增加堆栈的大小 -Xss
JVM 的参数;要么到 JVM 运行 ant
或通过设置 fork="true"
和一个 <compilerarg>
在 <javac>
任务。其实现在我想起来了,只要把这个问题放进去就可以解决吗? fork="true"
?
这是我发现的。发布我的问题后,我继续使用属性修改编译任务 fork="true"
, memoryinitialsize="256m"
和 memorymaximumsize="1024m"
(今天发现这是 Kieron 和 jmanning2k 建议的,感谢您的宝贵时间)。尽管如此,这并没有解决问题。
我决定开始从源代码树中删除类,看看是否可以查明问题。结果我们有一个 Web 服务客户端类 轴1.4 这是从 WSDL 文件自动生成的。现在,这个类是一个怪物(就像弗兰肯斯坦一样),它有 167 个字段成员(全部都是 String 类型)、167 个 getter/setter 对(每个字段 1 个)、一个接收所有 167 个字段作为参数的构造函数、一个equals 方法以一种奇怪的方式比较所有 167 个字段。对于每个字段,比较如下:
(this.A == null && other.getA() == null) || (this.A != null && this.A.equals(other.getA()))
该比较的结果与下一个字段的比较结果进行“与”(&&),依此类推。该类继续使用也使用所有字段的 hashCode 方法、一些自定义 XML 序列化方法以及返回描述该类且也使用所有字段成员的特定于 Axis 的元数据对象的方法。
这个类从未被修改,所以我只是将编译版本放在应用程序类路径中,并且项目编译没有问题。
现在,我知道删除这个单个源文件可以解决问题。但是,我完全不知道为什么这个特定的类会导致这个问题。很高兴知道;什么会导致 Java 代码编译期间出现 StackOverflowError?我想我会发布这个问题。
对于那些感兴趣的人:
- Windows XP SP2
- SUN的JDK 1.4.2_17
- 蚂蚁1.7.0