簡體   English   中英

螞蟻的<javac>任務拋出 StackOverflowException

[英]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.10Java 虛擬機的限制

修復 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? 我想我會發布這個問題。

對於那些有興趣的人:

  • 視窗 XP SP2
  • SUN 的 JDK 1.4.2_17
  • 螞蟻 1.7.0

其他一些答案提到了需要設置fork="true"修復程序,但另一種選擇是通過設置ANT_OPTS環境變量來增加由 ant 創建的底層 JVM 的堆棧空間:

ANT_OPTS=-Xss10M ant

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM