Задачи Ant <javac> вызывают исключение StackOverflowException
Вопрос
Я пытаюсь скомпилировать более 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.Если я снова запускаю задачу, компилятор выполняет инкрементную сборку, и все работает нормально.Это нежелательно, поскольку мы используем Управление круизом выполнять автоматическую ежедневную сборку, и это приводит к ложным сбоям сборки.
В качестве быстрого решения я создал 2 отдельные задачи, скомпилировав части проекта в каждой.Я действительно не думаю, что это решение сработает, поскольку в будущем будет добавлено больше классов, и я не хочу добавлять новые задачи компиляции каждый раз, когда мы достигаем "предела компиляции".
Решение
Было бы приятно узнать;что может вызывать или вызывает 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
Я подумай лимит стека для javac по умолчанию равен 512 КБ.Вы можете увеличить размер стека для этого компилятора до 10 МБ с помощью этой команды:
javac -J-Xss10M Foo.java
Возможно, вы сможете передать это в Ant-файл с помощью параметр compilerarg элемент, вложенный в ваш 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"
, не уверен, позволяет ли это вам устанавливать значения для стека и кучи (aka -Xm1024), но это может помочь (если это будет работать из командной строки, но не в Ant).
[Править]:Добавлена ссылка - the javac
задача страница, по-видимому, предполагает, что приведенные выше параметры требуют, чтобы вы также установили fork="true"
.
Происходит ли это, когда вы запускаете команду javac из командной строки?Возможно, вы захотите попробовать вилка атрибут.
Это довольно странно, 100 классов на самом деле - это не так уж много.Что делает компилятор при переполнении стека?Генерируется ли полезная трассировка стека?Что произойдет, если вы побежите javac
непосредственно в командной строке, а не через ant?
Одним из возможных обходных путей является простое увеличение размера стека с помощью -Xss
аргумент для JVM;либо к запущенной JVM ant
или установив fork="true"
и еще <compilerarg>
на <javac>
задание.На самом деле, теперь, когда я думаю об этом, исчезает ли проблема, просто вставив fork="true"
?
Вот что я нашел.После публикации моего вопроса я продолжил и изменил задачу компиляции с помощью атрибутов fork="true"
, memoryinitialsize="256m"
и memorymaximumsize="1024m"
(сегодня я обнаружил, что это было предложено Кироном и jmanning2k, спасибо за ваше время).Тем не менее, это не решило проблему.
Я решил начать удалять классы из исходного дерева, чтобы посмотреть, сможет ли a точно определить проблему.Оказывается, у нас был клиентский класс веб-сервиса для Ось 1.4 это было автоматически сгенерировано из файла WSDL.Итак, этот класс - монстр (как во Frankenstein), у него есть 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 и метода, который возвращает объект метаданных, специфичный для оси, который описывает класс и который также использует все элементы поля.
Этот класс никогда не изменяется, поэтому я просто помещаю скомпилированную версию в путь к классу приложения, и проект компилируется без проблем.
Теперь я знаю, что удаление этого единственного исходного файла решило проблему.Однако я абсолютно понятия не имею, почему именно этот класс вызвал проблему.Было бы приятно узнать;что может вызвать или вызывает StackOverflowError во время компиляции Java-кода?Я думаю, что опубликую этот вопрос.
Для тех, кто заинтересован:
- Windows XP с пакетом обновления 2
- SUN's JDK 1.4.2_17
- Муравей 1.7.0