错误消息“尝试在堆栈上拆分长或双”表示什么?

时间:2011-05-23 14:00:50

标签: java verifyerror

我的代码出现以下错误:

  

尝试在堆栈上拆分long或double

我对这个错误的起源一无所知,也不知道如何调试它。这表明什么问题?我该如何解决?

[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 个答案:

答案 0 :(得分:4)

这似乎是一个验证错误,表明正在加载的字节代码不是 与您的vm /编译器完全兼容。最有可能的是它来自外部库 您使用的,或者可能在构建过程中生成并指出错误。

您是否(直接或间接)使用任何生成的字节码?它经常与AOP一起使用。

Google也为此错误提供了大量点击。阅读它们,看看是否符合要求。

答案 1 :(得分:4)

对于very simple reason that

,Java虚拟机对涉及长数据类型和双数据类型的操作执行其他验证
  

long或double类型的值   连续两次占据当地   变量。这样的价值可能只是   使用较小的索引解决。对于   例如,存储类型double的值   在索引n的局部变量数组中   实际上占用了局部变量   索引n和n + 1;然而   索引n + 1处的局部变量不能   装载自。它可以存储到。   但是,这样做会使   局部变量的内容n。

当验证器确定使用了不正确的指令来访问long或double变量时(例如,尝试在索引n处处理局部变量的指令,作为整数或浮点数,将双/长分割)变量),然后标记所述错误。

除了修复生成此字节代码的字节码生成器之外,在这种情况下不能做很多事情。这可能是Java编译器本身,或任何字节代码操作框架,如ASM,cglib或Javassist。

修改

查看堆栈跟踪后,似乎所讨论的类恰好是生成的servlet(来自dashboard.jsp)。值得检查一下JDK的升级是否会解决这个问题。

答案 2 :(得分:1)

这是java.lang.VerifyError的可能消息,当“验证程序”检测到类文件虽然格式正确,包含某种内部不一致或安全问题时,会抛出

JVM规范说明(4.4.5):

  

所有8字节常量占用类文件的constant_pool表中的两个条目。如果CONSTANT_Long_infoCONSTANT_Double_info结构是索引n处constant_pool表中的项,则池中的下一个可用项位于索引n+2。 <{1}}索引constant_pool必须有效,但视为无法使用。

所以实际猜测,在类文件上有一个违反此规则的常量池。这不会(不应该)发生在普通的Java编译器中,但是有更多的方法可以创建和更改类文件(AOP,BCEL,混淆或其他编程语言)。尝试获取堆栈跟踪,它应该提供有问题的类文件。

进一步阅读

答案 3 :(得分:1)

我可以想到一个涉及自动装箱的案例:您是否尝试使用自动装箱存储浮动装置?如果这些最终被自动装入Double,那么当你将它们从堆栈中拉回时(可能是由于JVM错误),因为float占用的字节数少于双倍,字节大小检查失败并抛出此错误。这似乎是openjdk查看(某些)他们的源代码的情况 - 我猜这同样适用于Sun(对不起,Oracle!)JDK。

答案 4 :(得分:-1)

可以通过更改代码来解决问题:

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

成:

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