2008-08-19 5 views
4

Я пытаюсь собрать более 100 Java классов из различных пакетов из чистого каталога (без инкрементного компилирует) с использованием следующих муравьиных задач:<javac> задачи Ant бросает StackOverflowException

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

+1

Он выбрасывает исключение StackOverflowException - так вы обвиняете нас? :-) – kenj0418 2009-06-25 05:10:55

+0

@ kenj0418 - Ваш комментарий действительно заставил меня почесать голову, пока я не увидел смайлик. Неплохо! – 2009-06-25 18:18:19

ответ

4

It will be nice to know; what can cause or causes a StackOverflowError during compilation of Java code?

Вполне вероятно, что оценка длинное выражение в ваш java-файл потребляет много памяти, и поскольку это выполняется в сочетании с компиляцией других классов, виртуальная машина просто запускается s из пространства стека. Ваш сгенерированный класс, возможно, подталкивает законные пределы его содержания. См. Главу 4.10 Limitations of the Java Virtual Machine в редакции The Java Virtual Machine Specification, Second Edition.

Fix 1: реорганизовать класс

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

Fix 2: увеличить размер стека

Я думаю Kieron имеет одно решение, когда он упоминает -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> 
1

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

1

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

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

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

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

0

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

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

0

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

Я решил начать удаление классов из исходного дерева, чтобы узнать, может ли проблема определить проблему. Оказывается, у нас был класс клиентов Web Service для Axis 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())) 

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

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

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

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

  • Windows XP SP2
  • SUN в JDK 1.4.2_17
  • Ant 1.7.0
1
<javac srcdir="gen" destdir="gen-bin" debug="on" fork="true"> 
     <compilerarg value="-J-Xss10M" /> 
    </javac> 

из comment above неверен.Вам нужно пространство между -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: неверный флаг: -т- Xss1m [javac] Использование: javac