[英]Ant's <javac> tasks throws StackOverflowException
我正在嘗試使用以下 ant 任務從干凈的目錄(無增量編譯)中編譯來自不同包的 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。 如果我再次運行該任務,編譯器會進行增量構建,並且一切正常。 這是不可取的,因為我們使用CruiseControl進行每日自動構建,這會導致錯誤的構建失敗。
作為一個快速而骯臟的解決方案,我創建了 2 個單獨的任務,在每個任務中編譯項目的一部分。 我真的不認為這個解決方案會隨着未來添加更多類而成立,而且我不想每次達到“編譯限制”時都添加新的編譯任務。
很高興知道; 在 Java 代碼編譯期間,什么會導致或導致 StackOverflowError?
評估您的 java 文件中的長表達式很可能會消耗大量內存,並且因為這是與其他類的編譯一起完成的,所以 VM 會耗盡堆棧空間。 您生成的類可能正在推動其內容的法律限制。 請參閱The Java Virtual Machine Specification, Second Edition 中的第4.10章Java 虛擬機的限制。
修復 1:重構類
由於您的類正在生成,因此這可能不是一個選項。 盡管如此,還是值得看看你的類生成工具提供的選項,看看它是否可以產生不那么麻煩的東西。
修復 2:增加堆棧大小
我認為Kieron在提到 -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任務中嵌套一個compilerarg元素。
<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 命令時會發生這種情況嗎? 您可能想嘗試fork屬性。
嘗試將這些屬性的一些變體添加到Ant javac
任務行:
memoryinitialsize="256M" memorymaximumsize="1024M"
您也可以嘗試fork="true"
,不確定這是否允許您為堆棧和堆(又名 -Xm1024)設置值,但它可能會有所幫助(如果它可以從命令行運行,但不能在 Ant 中運行)。
[編輯]:添加了鏈接javac
任務頁面似乎建議上述參數要求您還設置fork="true"
。
這很奇怪,100 個班級真的不多。 堆棧溢出時編譯器在做什么? 是否生成了有用的堆棧跟蹤? 如果直接在命令行上運行javac
而不是通過 ant 會發生什么?
一種可能的解決方法是使用 JVM 的-Xss
參數簡單地增加堆棧的大小; 要么到運行ant
的 JVM,要么通過在<javac>
任務上設置fork="true"
和一個<compilerarg>
。 實際上,現在我想起來了,只要輸入fork="true"
問題就會消失嗎?
這是我發現的。 發布我的問題后,我繼續使用屬性fork="true"
、 memoryinitialsize="256m"
和memorymaximumsize="1024m"
修改編譯任務(今天發現這是 Kieron 和 jmanning2k 建議的,感謝您的時間) . 盡管如此,這並沒有解決問題。
我決定開始從源樹中刪除類,看看是否可以查明問題。 結果我們有一個用於Axis 1.4的 Web 服務客戶端類,它是從 WSDL 文件自動生成的。 現在,這個類是一個怪物(就像在 Frankenstein 中一樣),它有 167 個字段成員(它們都是 String 類型),167 個 getter/setter 對(每個字段 1 個),一個接收所有 167 個字段作為參數的構造函數,一個以一種奇怪的方式比較所有 167 個字段的 equals 方法。 對於每個字段,比較如下:
(this.A == null && other.getA() == null) || (this.A != null && this.A.equals(other.getA()))
此比較的結果與下一個字段的比較結果“與”(&&),依此類推。 該類繼續使用 hashCode 方法,該方法也使用所有字段、一些自定義 XML 序列化方法和一個方法,該方法返回一個特定於 Axis 的元數據對象,該對象描述該類並且還使用所有字段成員。
這個類永遠不會被修改,所以我只是在應用程序類路徑中放了一個編譯版本,項目編譯沒有問題。
現在,我知道刪除這個單一的源文件解決了這個問題。 但是,我完全不知道為什么這個特定的類會導致這個問題。 很高興知道; 在 Java 代碼編譯期間,什么會導致或導致 StackOverflowError? 我想我會發布這個問題。
對於那些有興趣的人:
其他一些答案提到了需要設置fork="true"
修復程序,但另一種選擇是通過設置ANT_OPTS
環境變量來增加由 ant 創建的底層 JVM 的堆棧空間:
ANT_OPTS=-Xss10M ant
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.