10

我从我的代码中收到以下错误:

尝试在堆栈上拆分 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);
}

这段代码对数据有什么影响吗?

4

5 回答 5

4

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

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

谷歌也为这个错误提供了很多点击。阅读它们,看看是否符合要求。

于 2011-05-23T14:13:38.057 回答
4

Java 虚拟机对涉及 long 和 double 数据类型的操作执行额外的验证,原因非常简单:

long 或 double 类型的值占用两个连续的局部变量。这样的值只能使用较小的索引来解决。例如,存储在索引 n 处的局部变量数组中的 double 类型的值实际上占用了索引为 n 和 n +1 的局部变量;但是,不能从中加载索引 n +1 处的局部变量。可以存入。但是,这样做会使局部变量 n 的内容无效。

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

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

编辑:

查看堆栈跟踪后,似乎有问题的类恰好是生成的 servlet(来自dashboard.jsp)。值得检查一下涉及编译已翻译 JSP 的 JDK 升级是否会解决该问题。

于 2011-05-23T14:34:18.383 回答
1

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

JVM 规范说明(4.4.5):

constant_pool所有 8 字节的常量在类文件的表中占据两个条目。如果 a CONSTANT_Long_infoorCONSTANT_Double_info结构是constant_pool表中索引 n 处的项目,则池中的下一个可用项目位于索引处n+2constant_pool索引n+1必须有效但被视为不可用。

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

延伸阅读

于 2011-05-23T14:13:14.800 回答
1

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

于 2011-05-23T14:16:46.957 回答
-1

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

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

进入:

for (Long serviceId : test) {
    Service service = dashboardViewModel.getService(serviceId);
}
于 2014-05-30T03:01:28.833 回答