Задачи Ant <javac>вызывают исключение StackOverflowException - PullRequest
5 голосов
/ 20 августа 2008

Я пытаюсь собрать более 100 классов Java из разных пакетов из чистого директории (без инкрементных компиляций) с использованием следующих задач ant:

<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 отдельные задачи, в каждой из которых были собраны части проекта. Я действительно не думаю, что это решение сохранится, поскольку в будущем будет добавлено больше классов, и я не хочу добавлять новые задачи компиляции каждый раз, когда мы достигаем «предела компиляции».

Ответы [ 6 ]

5 голосов
/ 21 августа 2008

Будет приятно узнать; что можешь вызывает или вызывает StackOverflowError во время компиляции кода Java?

Вполне вероятно, что оценка длинного выражения в вашем java-файле потребляет много памяти, и поскольку это делается в сочетании с компиляцией других классов, виртуальной машине просто не хватает места в стеке. Ваш сгенерированный класс, возможно, выдвигает законные пределы для его содержания. См. Главу 4.10 Ограничения виртуальной машины Java в Спецификация виртуальной машины Java, второе издание .

Исправление 1: рефакторинг класса

Так как ваш класс генерируется, это может быть не вариант. Тем не менее, стоит взглянуть на варианты, которые предлагает ваш инструмент генерации классов, чтобы увидеть, может ли он создать что-то менее хлопотное.

Исправление 2: увеличение размера стека

Я думаю, У Кирона есть одно решение, когда он упоминает аргумент -Xss. javac принимает несколько нестандартных аргументов, которые могут различаться в зависимости от версии и поставщика компилятора.

Мой компилятор:

$ javac -version
javac 1.6.0_05

Чтобы перечислить все опции для этого, я бы использовал эти команды:

javac -help
javac -X
javac -J-X

I думаю ограничение стека для javac по умолчанию составляет 512Kb. Вы можете увеличить размер стека для этого компилятора до 10 Мб с помощью этой команды:

javac -J-Xss10M Foo.java

Возможно, вы сможете передать это в файл Ant с элементом compilerarg , вложенным в вашу задачу javac .

<javac srcdir="gen" destdir="gen-bin" debug="on" fork="true">
    <compilerarg value="-J-Xss10M" />
</javac>
2 голосов
/ 25 июня 2009
  <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

1 голос
/ 20 августа 2008

Попробуйте добавить некоторые варианты этих атрибутов в строку Ant javac task :

memoryinitialsize="256M" memorymaximumsize="1024M"

Вы также можете попробовать fork="true", но не уверены, что это позволяет вам устанавливать значения для стека и кучи (иначе -Xm1024), но это может помочь (если это будет работать из командной строки, но не в Ant).

[Изменить]: Добавленная ссылка - страница javac task , по-видимому, предполагает, что для указанных выше параметров необходимо также установить fork="true".

1 голос
/ 20 августа 2008

Это происходит, когда вы запускаете команду javac из командной строки? Возможно, вы захотите попробовать атрибут fork .

0 голосов
/ 20 августа 2008

Вот что я нашел. После публикации моего вопроса я продолжил и изменил задачу компиляции с атрибутами fork="true", memoryinitialsize="256m" и memorymaximumsize="1024m" (сегодня выяснилось, что это было предложено Kieron и jmanning2k, спасибо за ваше время). Тем не менее, это не решило проблему.

Я решил начать удалять классы из дерева исходных текстов, чтобы посмотреть, может ли проблема определить проблему. Оказывается, у нас был класс клиента веб-службы для Axis 1.4 , который был автоматически сгенерирован из файла WSDL. Теперь этот класс является монстром (как во Франкенштейне), он имеет 167 членов поля (все из них имеют тип String), 167 пар получатель / установщик (1 для каждого поля), конструктор, который получает все 167 полей в качестве параметров, метод equals, который сравнивает все 167 полей странным образом. Для каждого поля сравнение выглядит так:

(this.A == null && other.getA() == null) || (this.A != null && this.A.equals(other.getA()))

Результат этого сравнения "anded" (&&) с результатом сравнения следующего поля и т. Д. Класс продолжает метод hashCode, который также использует все поля, некоторые пользовательские методы сериализации XML и метод, который возвращает объект метаданных, специфичный для Axis, который описывает класс и который также использует все члены поля.

Этот класс никогда не изменяется, поэтому я просто помещаю скомпилированную версию в путь к классам приложения, и проект компилируется без проблем.

Теперь я знаю, что удаление этого единственного исходного файла решило проблему. Однако я абсолютно не знаю, почему именно этот класс вызвал проблему. Будет приятно узнать; что может вызвать или вызывает StackOverflowError во время компиляции кода Java? Я думаю, я отправлю этот вопрос.

Для заинтересованных:

  • Windows XP SP2
  • JDK СОЛНЦА 1.4.2_17
  • Муравей 1.7.0
0 голосов
/ 20 августа 2008

Это довольно странно, 100 классов на самом деле не так много. Что делает компилятор при переполнении стека? Создана ли полезная трассировка стека? Что произойдет, если вы запустите javac непосредственно в командной строке вместо файла thorgh ant?

Один из возможных обходных путей - просто увеличить размер стека с помощью аргумента -Xss для JVM; либо для JVM, работающей ant, либо путем установки fork="true" и <compilerarg> в задаче <javac>. На самом деле, теперь, когда я думаю об этом, проблема уходит, просто вставив fork="true"?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...