Что означает сообщение об ошибке «Попытка разбить длинный или двойной на стеке»? - PullRequest
10 голосов
/ 23 мая 2011

Я получаю следующую ошибку из моего кода:

Попытка разбить длинное или двойное в стеке

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

[ERROR]  [Mon May 23 14:29:46 IST 2011]   [(class: org/apache/jsp/dashboard_jsp, method: _jspService signature:     (Ljavax/servlet/http/HttpServletRequest;Ljavax/servlet/http/HttpServletResponse;)V) Attempt to split long or double on the stack]  [10.97.34.222] hddlntdsz2350  [ session not set ] 
java.lang.VerifyError: (class: org/apache/jsp/dashboard_jsp, method: _jspService signature: (Ljavax/servlet/http/HttpServletRequest;Ljavax/servlet/http/HttpServletResponse;)V) Attempt to split long or double on the stack
at java.lang.Class.getDeclaredConstructors0(Native Method)
at java.lang.Class.privateGetDeclaredConstructors(Class.java:2389)
at java.lang.Class.getConstructor0(Class.java:2699)
at java.lang.Class.newInstance0(Class.java:326)
at java.lang.Class.newInstance(Class.java:308)
at org.jboss.web.tomcat.service.TomcatInjectionContainer.newInstance(TomcatInjectionContainer.java:273)

Код проблемы: я создал модель, как указано ниже

public class DashboardViewModel implements Serializable {

/** defalut serialization id */
private static final long serialVersionUID = 1L;

/**
 * Collection representing all the services
 */
private Map<Long, ServiceCustomerModel> serviceDataMap;

}

На определенной странице JSP яделаю следующее.

for (Long serviceId : dashboardViewModel.getServices()) {
           Service service = dashboardViewModel.getService(serviceId);
}

Метод getServices в вышеприведенном целевом классе выглядит следующим образом:

public Set<Long> getServices() {
    return this.serviceDataMap.keySet();
}

При включении вышеуказанного кода в jsp.Я получаю ошибку.В противном случае это работает.

Дальнейшие исследования:

Я обновил файл dashboard.jsp следующим фрагментом кода.Я не могу определить, почему, но этот код работает.

ArrayList<Long> test = new ArrayList<Long>();
test.addAll(dashboardViewModel.getServices());
for (long serviceId : test) {
    Service service = dashboardViewModel.getService(serviceId);
}

Имеет ли этот код какое-либо значение для данных?

Ответы [ 5 ]

4 голосов
/ 23 мая 2011

Виртуальная машина Java выполняет дополнительную проверку операций, включающих длинные и двойные типы данных, по очень простой причине , что

Значение типа long или типа double занимает два последовательных местных переменные. Такое значение может быть только адресовано с использованием меньшего индекса. За Например, значение типа double сохраняется в массиве локальных переменных с индексом n на самом деле занимает локальные переменные с индексами n и n +1; Тем не менее локальная переменная с индексом n +1 не может быть загружен из. Это может быть сохранено в. Тем не менее, это делает недействительным содержимое локальной переменной n.

Когда верификатор определяет, что неверная инструкция используется для доступа к длинной или двойной переменной (скажем, инструкция, которая пытается обработать локальную переменную с индексом n, как целое число или число с плавающей запятой, которая разбивает double / long переменная), то указанная ошибка помечается.

В этом случае не так много можно сделать, кроме как исправить генератор байт-кода, который сгенерировал этот байт-код. Это может быть сам компилятор Java или любая из структур манипулирования байтовым кодом, например ASM, cglib или Javassist.

Изменить:

После просмотра трассировки стека выясняется, что рассматриваемый класс является сгенерированным сервлетом (из dashboard.jsp). Было бы целесообразно проверить, решит ли проблему обновление JDK, включающее компиляцию переведенного JSP.

4 голосов
/ 23 мая 2011

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

Используете ли вы (прямо или косвенно) какой-либо сгенерированный байт-код?Это часто используется с AOP.

Также Google дает много хитов для этой ошибки.Прочитайте их, посмотрите, отвечает ли что-либо требованиям.

1 голос
/ 23 мая 2011

Я могу вспомнить случай, который включает в себя автобокс: вы пытаетесь использовать автобокс для хранения поплавков? Если они автоматически помещаются в Double, то когда вы вытаскиваете их из стека (возможно, из-за ошибки JVM), потому что float занимает меньше байтов, чем удваивается, проверка размера байта завершается неудачей, и эта ошибка выдается. Это похоже на случай, когда openjdk просматривает (некоторые из них) свой исходный код - я полагаю, что то же самое применимо к JDK для Sun (извините, Oracle!).

1 голос
/ 23 мая 2011

Это возможное сообщение java.lang.VerifyError, которое выдается , когда «верификатор» обнаруживает, что файл класса, хотя и правильно сформированный, содержит какие-то внутренние несоответствия или проблемы безопасности.

Примечания к спецификации JVM (4.4.5):

Все 8-байтовые константы занимают две записи в таблице constant_pool файла класса.Если структура CONSTANT_Long_info или CONSTANT_Double_info является элементом в таблице constant_pool с индексом n, то следующий используемый элемент в пуле находится с индексом n+2.constant_pool index n+1 должен быть допустимым, но считается непригодным для использования.

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

Дальнейшее чтение

0 голосов
/ 30 мая 2014

Можно ли решить проблему, изменив код:

for (long serviceId : test) {
    Service service = dashboardViewModel.getService(serviceId);
}

на:

for (Long serviceId : test) {
    Service service = dashboardViewModel.getService(serviceId);
}
...