Насколько безопасно использовать -XX: -UseSplitVerifier?

Известны проблемы совместимости с скомпилированным кодом JDK7 с использованием инструментария. Что касается http://www.oracle.com/technetwork/java/javase/compatibility-417013.html

Classfiles с номером версии 51 проверяются исключительно с помощью верификатора проверки типов, и, следовательно, при необходимости методы должны иметь атрибуты StackMapTable. Для файлов классов с версией 50 JVM Hotspot будет (и продолжает) отказоустойчивость к верификатору ввода-вывода, если файлы стека в файле отсутствуют или неверны. Такое поведение при отказе не возникает для файлов классов с версией 51 (версия по умолчанию для Java SE 7). Любой инструмент, который модифицирует байт-код в файле класса версии 51, обязательно должен обновить информацию о стеке, чтобы она соответствовала байт-коду, чтобы пройти проверку.

Решение состоит в том, чтобы использовать -XX:-UseSplitVerifier, как описано здесь: http://weblogs.java.net/blog/fabriziogiudici/archive/2012/05/07/understanding-subtle-new-behaviours-jdk-7

Насколько это безопасно? Я полагаю, что Oracle поместила эту проверку по какой-то причине. Если я его не использую, я могу рискнуть и на другие проблемы.

Каковы могут быть последствия использования -XX:-UseSplitVerifier?

Спасибо,

Петр.

Ответ 1

Короче говоря, это абсолютно безопасно.

Так как Java 6, компилятор Oracle создал файлы классов с помощью StackMapTable. Основная идея заключается в том, что компилятор может явно указать, что такое тип объекта, вместо того, чтобы сделать это время выполнения. Это обеспечивает небольшое ускорение во время выполнения, в обмен на некоторое дополнительное время во время компиляции и некоторую сложность в файле скомпилированного класса (вышеупомянутый StackMapTable).

В качестве экспериментальной функции он не был включен по умолчанию в компиляторе Java 6. По умолчанию среда выполнения проверяет сами типы объектов, если не существует StackMapTable.

До Java 7. Oracle сделал это обязательным: компилятор создает их, и среда выполнения проверяет их. Он по-прежнему использует старый верификатор, если StackMapTable не существует... но только в файлах классов с Java 6 или ранее (версия 50). Для использования StackMapTable требуются файлы классов Java 7 (версия 51), поэтому среда выполнения не будет обрезать их одинаково.

Это только проблема, если ваши файлы классов были созданы без StackMapTable. Например, если вы использовали не-Oracle JVM. Или если вы перепутали байт-код после этого - как инструмент для его использования с анализатором отладчика, оптимизатора или анализатора кода.

Но вы можете обойти это! Oracle JVM предоставляет -XX: + UseSplitVerifier, чтобы заставить среду выполнения вернуться к верификатору старого типа. Он не заботится о StackMapTable.

На практике оптимизированная оптимизация скорости и эффективности во время выполнения не реализована: если она существует, этого недостаточно, чтобы кто-либо заметил. Поскольку верификатор нового типа не предоставляет никаких новых функций (просто оптимизация), совершенно безопасно отключить его.

Объяснение Oracle находится в http://www.oracle.com/technetwork/java/javase/compatibility-417013.html, если вы ищете JSR 202.

Ответ 2

Да - это безопасно. Как говорит Джудеберт, это немного замедляет загрузку классов.

Чтобы добавить немного больше информации: что такое таблица StackMap? Ну, верификатор Bytecode должен сделать два прохода над кодом в файле класса для проверки правильных типов данных, которые передаются и используются. Первый проход, который является более медленным, анализирует поток всех ветвей кода, чтобы увидеть, какие типы данных могут быть в стеке в каждой инструкции байткода. Второй проход рассматривает каждую инструкцию, чтобы убедиться, что она может действовать на всех этих типах.

Вот ключ: у компилятора уже есть вся информация, которую генерирует первый проход - поэтому (в Java 6 и 7) он хранит его в таблице StackMap в файле класса.

Это ускоряет загрузку классов, поскольку загрузчик классов не должен выполнять этот первый проход. Именно поэтому он назывался Split Verifier, потому что работа делится между компилятором и механизмом загрузки во время выполнения. Когда вы используете опцию -XX: -UseSplitVerifier, вы говорите Java, чтобы сделать оба прохода во время загрузки класса (и игнорировать любую таблицу StackMap). Многие продукты (например, профилировщики, которые изменяют байт-код во время загрузки) вначале не знали о таблице StackMap, поэтому, когда они модифицировали классы во время загрузки, таблица StackMap из компилятора устарела и вызвала ошибки.

SO, чтобы суммировать, опция -XX: -UseSplitVerifier замедляет загрузку классов. Это не влияет на безопасность, производительность и функциональность во время выполнения.

Ответ 3

В Java 7 были добавлены кадры фрейма, а "prashant" утверждает, что идея ошибочна и предлагает разработчикам всегда использовать флаг -XX:-UseSplitVerifier, чтобы избежать их использования.

Подробнее: Java 7 Bytecode Verifier: огромный шаг назад для JVM