Задачи Ant <javac> вызывают исключение StackOverflowException

StackOverflow https://stackoverflow.com/questions/16935

  •  08-06-2019
  •  | 
  •  

Вопрос

Я пытаюсь скомпилировать более 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
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top