java.lang.VerifyError: 栈映射与异常处理程序处的栈映射不匹配

13
面对 JVM 加载字节码时以下代码段所显示的 java.lang.VerifyError。
try{
-----
}  catch (NumberFormatException|CalculationException e) {

}
在这里,CalculationException是扩展java.lang.RuntimeException的自定义异常,而NumberFormatException是标准的Java RuntimeException。尽管代码在本地Windows机器上编译和运行良好,但在QA / Prod / Dev Unix节点之一上失败,并在其他Unix节点上正常工作。虽然两个Unix节点都具有相同的配置(使用RedHat 6.2和1.8 JDK以及相同版本的jar文件),并通过javap -c比较了两个节点生成的字节码,发现它们相同。我找到了两种方法来解决此问题。第一种方法是在开发Unix框中禁用字节码验证,方法为-Xverify:none。第二种方法是在catch块中使用父异常:RuntimeException,而不是结合两个异常。如果Java确实存在捕获方式问题,为什么编译器没有抱怨,为什么它在一个机器上运行而在另一个机器上无法运行,这个错误原因也让我感到困惑,它说:“CalculationException(当前帧,堆栈[0])无法分配给'java/lang/RuntimeException”,但根据测试,它实际上是可以分配的。
if (RuntimeException.class.isAssignableFrom(CalculationException.class)){
    System.out.println("Assisgnable");
}

完整异常细节: 位置:

    com/markit/valuations/marketdata/snapper/domain/credit/BeanWrapperBuilder_CDXOCompositeVolSurface.getSpreadVol(Lcom/markit/valuations/dates/ImmutableDate;Lcom/markit/valuations/marketdata/data/indexeddata/IndexedData;DLcom/markit/valuations/dates/ImmutableDate;Lcom/markit/valuations/dates/ImmutableDate;Ljava/lang/String;Ljava/lang/String;Lcom/markit/qag/analytics/credit/indexpv/swaption/CreditIndexSwaptionCalculator;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Double; @51: astore
  Reason:
    Type 'com/markit/valuations/common/CalculationException' (current frame, stack[0]) is not assignable to 'java/lang/RuntimeException' (stack map, stack[0])
  Current Frame:
    bci: @0
    flags: { }
    locals: { 'com/markit/valuations/marketdata/snapper/domain/credit/BeanWrapperBuilder_CDXOCompositeVolSurface', 'com/markit/valuations/dates/ImmutableDate', 'com/markit/valuations/marketdata/data/indexeddata/IndexedData', double, double_2nd, 'com/markit/valuations/dates/ImmutableDate', 'com/markit/valuations/dates/ImmutableDate', 'java/lang/String', 'java/lang/String', 'com/markit/qag/analytics/credit/indexpv/swaption/CreditIndexSwaptionCalculator', 'java/lang/String', 'java/lang/String' }
    stack: { 'com/markit/valuations/common/CalculationException' }
  Stackmap Frame:
    bci: @51
    flags: { }
    locals: { 'com/markit/valuations/marketdata/snapper/domain/credit/BeanWrapperBuilder_CDXOCompositeVolSurface', 'com/markit/valuations/dates/ImmutableDate', 'com/markit/valuations/marketdata/data/indexeddata/IndexedData', double, double_2nd, 'com/markit/valuations/dates/ImmutableDate', 'com/markit/valuations/dates/ImmutableDate', 'java/lang/String', 'java/lang/String', 'com/markit/qag/analytics/credit/indexpv/swaption/CreditIndexSwaptionCalculator', 'java/lang/String', 'java/lang/String' }
    stack: { 'java/lang/RuntimeException' }
  Bytecode:
    0x0000000: 2c19 0ab9 0015 0200 b800 cb2b 1906 ba00
    0x0000010: cc00 00b6 00cd ba00 ce00 00b6 00cf 1909
    0x0000020: ba00 d000 00b6 00cf 0eb8 003b b600 d1c0
    0x0000030: 0091 b03a 0cbb 0048 59b7 0049 12d3 b600
    0x0000040: 4b19 0ab6 004b 12d4 b600 4b2c 1254 b900
    0x0000050: 1502 00b6 004b 12d5 b600 4b29 b600 4c12
    0x0000060: d6b6 004b 1907 b600 4b12 d7b6 004b 1905
    0x0000070: b600 5b12 d8b6 004b 1906 b600 5b12 d9b6
    0x0000080: 004b 190b b600 4b12 dab6 004b 1908 b600
    0x0000090: 4bb6 004d 3a0d b200 4719 0d19 0cb9 0081
    0x00000a0: 0300 0eb8 003b b0
  Exception Handler Table:
    bci [0, 50] => handler: 51
    bci [0, 50] => handler: 51
  Stackmap Table:
  same_locals_1_stack_item_frame(@51,Object[#535])

3
首先猜测这台机器上的CalculationException版本不同。 - Holger
感谢@Holger,但是我已经验证了持有CalculationException.class的jar版本,它是相同的。即使它们的反编译代码和反汇编代码看起来也是一样的。 - tarunk
然后,就没有任何合理的情况了。正如你所指出的,这是一个有效的Java结构,在一台机器上运行正常。它应该能够工作。如果不是Java代码损坏的问题,也许是JDK安装有问题。除了重新安装(相当于关闭再打开),我不知道还能尝试什么... - Holger
1
也许这是一个类加载器问题。在早期版本中,异常是否曾经不是运行时异常?很有可能您的工件重复了,并从特定的加载器加载了错误的版本。 - Rafael Winterhalter
4
+1表示对-Xverify:none的支持。我在IntelliJ中的单元测试中遇到了类似的问题。通过这种解决方法,我可以再次对它们进行调试。 - anstue
显示剩余4条评论
3个回答

5

原因

这种情况通常是由于依赖项中存在相同库(Jar)的冲突版本引起的。更具体地说,我导入了不同版本的Jackson库v2.9.10和v2.11.0。

故障排除

以详细模式启动应用程序,并让Java记录加载的所有类,以查看冲突类来自哪里。可以通过传递标志-verbose:class来完成此操作。

解决方法

  • 删除冲突版本的依赖项,并确保所有相关依赖库的主要版本(至少)相同,最好连次要版本也相同。
  • 删除直接依赖项的传递导入冲突版本的依赖项。
  • 如果即使使用mvn dependency:tree或Maven Helper插件后仍未发现任何冲突依赖项,则可能是其中一个库类路径导入了冲突依赖项。虽然只有应用程序才应该具有类路径,但如果某人在库POM文件中添加了<addClasspath>true</addClasspath>,就会导致此问题。

1
对我来说,问题出在build.gradleplugins部分中使用了错误版本的Swagger依赖(它使用Jackson)。我使用的是为Jackson 2.9.10构建的内容,在包含Jackson 2.11.3的构建中使用。我使用--scan选项进行Gradle构建扫描时检测到了这个问题,可以看到插件依赖作为单独的依赖项与编译依赖项并列显示。 - arberg

0
依赖崩溃是原因,正如 Aditya 指出的那样。如果您正在使用 SBT,则可以通过以下方式解决它。
首先,在全局插件 ~/.sbt/1.0/plugins/plugins.sbt 中添加依赖图:
  • SBT 1.4+:添加
    addDependencyTreePlugin
    
  • SBT <1.3:添加
    addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.10.0-RC1")
    
在你的项目中运行以下命令:
sbt "whatDependsOn com.fasterxml.jackson.core jackson-databind"

出现冲突的库是jackson-databind,组织为com.fasterxml.jackson.core。我的问题也是因为play-json使用了2.10.4,而Confluent包使用了2.9.9。您需要根据收到的错误消息找到您的问题所在。

然后从这一点开始,您需要决定如何解决它。升级软件包、降级或排除库。在我的情况下,因为play-json是一个不太关键的库的传递依赖项,我选择了最简单的方法,将play-json库中的2.10.4排除掉。


-5

您需要在配置文件中设置以下JVM参数:

-XX:-UseSplitVerifier


2
关于这个答案,您需要更多的信息吗? - amer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接