Что означает сообщение об ошибке "Попытка разделить длинные или двойные стеки"?
Я получаю следующую ошибку из моего кода:
Попытка разделить длинный или двойной стек на стек
Я не знаю о происхождении этой ошибки и не знаю, как ее отладить. Что это за проблема? Как я могу это исправить?
[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);
}
Имеет ли этот код какое-либо значение для данных?
Ответы
Ответ 1
Виртуальная машина Java выполняет дополнительную проверку операций с длинными и двойными типами данных, для очень простая причина, по которой
Значение типа long или type double занимает два последовательных локальных переменные. Такое значение может быть с использованием меньшего индекса. Для Например, значение типа double сохраняется в локальном переменном массиве с индексом n фактически занимает локальные переменные с индексами n и n +1; Однако локальная переменная с индексом n +1 не может быть загружен из. Его можно хранить. Однако это делает недействительным содержимое локальной переменной n.
Когда верификатор определяет, что для доступа к длинной или двойной переменной используется некорректная команда (скажем, инструкция, которая пытается обрабатывать локальную переменную с индексом n, как целое число или поплавок, разделяющее double/long переменная), то указанная ошибка помечена.
В этом случае не так много можно сделать, за исключением исправления генератора байт-кода, который сгенерировал этот байт-код. Это может быть сам компилятор Java, или любой из механизмов манипулирования байтовым кодом, таких как ASM, cglib или Javassist.
Edit:
После просмотра stacktrace кажется, что рассматриваемый класс является сгенерированным сервлетом (из dashboard.jsp). Было бы целесообразно проверить, разрешит ли обновление JDK с использованием компиляции переведенного JSP.
Ответ 2
Кажется, это ошибка проверки, указывающая, что загружаемый байтовый код не является
полностью совместим с вашим vm/компилятором. Скорее всего, это происходит из внешней библиотеки
который вы используете или может быть сгенерирован в процессе сборки и указать ошибку.
Вы используете (прямо или косвенно) любой сгенерированный байт-код? Он часто используется с АОП.
Также Google дает много хитов за эту ошибку. Прочитайте их, посмотрите, подходит ли что-либо для счета.
Ответ 3
Это возможное сообщение java.lang.VerifyError
, которое вызывается, когда "верификатор" обнаруживает, что файл класса, хотя и хорошо сформированный, содержит какие-то внутренние непоследовательности или проблемы с безопасностью.
Примечания к спецификации JVM (4.4.5):
Все 8-байтовые константы занимают две записи в таблице constant_pool
файла класса. Если структура CONSTANT_Long_info
или CONSTANT_Double_info
является элементом таблицы constant_pool
в индексе n, то следующий полезный элемент в пуле находится в индексе n+2
. Индекс constant_pool
n+1
должен быть действительным, но считается непригодным.
Так на самом деле догадаться, что в файле класса есть постоянный пул, который нарушает это правило. Это не будет (не должно) происходить с обычным java-компилятором, но есть больше способов создания и изменения файлов классов (AOP, BCEL, обфускации или других языков программирования). Попытайтесь получить stacktrace, он должен дать подсказку для файла-нарушителя.
Дополнительная литература
Ответ 4
Я могу придумать случай, который включает автобоксинг: пытаетесь ли вы использовать autoboxing для хранения float? Если они автоматически деактивируются в Double, тогда, когда вы вытаскиваете их из стека (возможно, из-за ошибки JVM), поскольку float занимает меньше байтов, чем double, проверка размера байта завершается неудачно, и эта ошибка возникает. Это похоже на openjdk, смотрящий на (некоторые) их исходный код - я предполагаю, что то же самое применимо к Sun (извините, Oracle!) JDK.
Ответ 5
Можно ли устранить проблему, изменив код:
for (long serviceId : test) {
Service service = dashboardViewModel.getService(serviceId);
}
в
for (long serviceId : test) {
Service service = dashboardViewModel.getService(serviceId);
}