【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>
先说遇到的问题,Hasor 在1.6 和早期 1.7 jdk 下运行 asm 动态生成的字节码无任何异常。接着有反馈在 java8下出现类似如下异常,一开始并没有里会这个异常信息。找到一个解决办法是增加一个 -noverify 参数来压制这个校验异常。
最近比较好奇想寻找一下究竟为什么会出现 VerifyError 错误,下面是这个错误的全貌。
2017-02-15 11:03:47.423 [RSF-Nio-4] INFO - connected form 127.0.0.1:60618
2017-02-15 11:03:47.440 [RSF-Biz-1] ERROR - do request(12345) failed -> service [RSF]net.hasor.website.client.ProjectService-1.0.0, error :(net.hasor.core.utils.UnhandledException)java.lang.VerifyError - Inconsistent stackmap frames at branch target 101
Exception Details:
Location:
net/hasor/website/manager/UserManager$A_19.loginUpdate(Lnet/hasor/website/domain/UserDO;Ljava/lang/String;)V @101: new
Reason:
Type top (current frame, locals[3]) is not assignable to 'java/lang/Throwable' (stack map, locals[3])
Current Frame:
bci: @92
flags: { }
locals: { 'net/hasor/website/manager/UserManager$A_19', 'net/hasor/website/domain/UserDO', 'java/lang/String', top, top, 'java/lang/Throwable' }
stack: { integer }
Stackmap Frame:
bci: @101
flags: { }
locals: { 'net/hasor/website/manager/UserManager$A_19', 'net/hasor/website/domain/UserDO', 'java/lang/String', 'java/lang/Throwable' }
stack: { }
Bytecode:
0x0000000: 1002 bd00 0659 1000 1208 5359 1001 120a
0x0000010: 533a 0410 02bd 000c 5910 002b 5359 1001
0x0000020: 2c53 3a05 2ab6 0012 1213 1904 b600 173a
0x0000030: 06bb 0019 5919 062a 1905 b700 1d3a 07bb
0x0000040: 001f 5912 2119 0619 07b7 0024 b600 283a
0x0000050: 0819 0857 b13a 0519 05c1 002a 9900 0919
0x0000060: 05c0 002a bfbb 002a 5919 05b7 002d bf
Exception Handler Table:
bci [0, 83] => handler: 85
Stackmap Table:
same_locals_1_stack_item_extended(@85,Object[#4])
append_frame(@101,Object[#4])
net.hasor.core.utils.UnhandledException: java.lang.VerifyError - Inconsistent stackmap frames at branch target 101
Exception Details:
Location:
net/hasor/website/manager/UserManager$A_19.loginUpdate(Lnet/hasor/website/domain/UserDO;Ljava/lang/String;)V @101: new
Reason:
Type top (current frame, locals[3]) is not assignable to 'java/lang/Throwable' (stack map, locals[3])
Current Frame:
bci: @92
flags: { }
locals: { 'net/hasor/website/manager/UserManager$A_19', 'net/hasor/website/domain/UserDO', 'java/lang/String', top, top, 'java/lang/Throwable' }
stack: { integer }
Stackmap Frame:
bci: @101
flags: { }
locals: { 'net/hasor/website/manager/UserManager$A_19', 'net/hasor/website/domain/UserDO', 'java/lang/String', 'java/lang/Throwable' }
stack: { }
Bytecode:
0x0000000: 1002 bd00 0659 1000 1208 5359 1001 120a
0x0000010: 533a 0410 02bd 000c 5910 002b 5359 1001
0x0000020: 2c53 3a05 2ab6 0012 1213 1904 b600 173a
0x0000030: 06bb 0019 5919 062a 1905 b700 1d3a 07bb
0x0000040: 001f 5912 2119 0619 07b7 0024 b600 283a
0x0000050: 0819 0857 b13a 0519 05c1 002a 9900 0919
0x0000060: 05c0 002a bfbb 002a 5919 05b7 002d bf
Exception Handler Table:
bci [0, 83] => handler: 85
Stackmap Table:
same_locals_1_stack_item_extended(@85,Object[#4])
append_frame(@101,Object[#4])
at net.hasor.core.utils.ExceptionUtils.toRuntimeException(ExceptionUtils.java:28) ~[classes/:na]
at net.hasor.core.container.TemplateBeanBuilder.createObject(TemplateBeanBuilder.java:159) ~[classes/:na]
at net.hasor.core.container.BeanContainer.callSuperCreateObject(BeanContainer.java:156) ~[classes/:na]
at net.hasor.core.container.BeanContainer.access$000(BeanContainer.java:42) ~[classes/:na]
at net.hasor.core.container.BeanContainer$1.get(BeanContainer.java:144) ~[classes/:na]
at net.hasor.core.provider.SingleProvider.get(SingleProvider.java:35) ~[classes/:na]
at net.hasor.core.container.BeanContainer.createObject(BeanContainer.java:142) ~[classes/:na]
at net.hasor.core.container.TemplateBeanBuilder.getDefaultInstance(TemplateBeanBuilder.java:88) ~[classes/:na]
at net.hasor.core.context.TemplateAppContext$1.get(TemplateAppContext.java:149) ~[classes/:na]
at net.hasor.core.context.TemplateAppContext.getInstance(TemplateAppContext.java:98) ~[classes/:na]
at net.hasor.core.container.TemplateBeanBuilder.injInject(TemplateBeanBuilder.java:249) ~[classes/:na]
at net.hasor.core.container.TemplateBeanBuilder.injectObject(TemplateBeanBuilder.java:232) ~[classes/:na]
at net.hasor.core.container.TemplateBeanBuilder.doInject(TemplateBeanBuilder.java:176) ~[classes/:na]
at net.hasor.core.container.TemplateBeanBuilder.createObject(TemplateBeanBuilder.java:149) ~[classes/:na]
at net.hasor.core.container.BeanContainer.callSuperCreateObject(BeanContainer.java:156) ~[classes/:na]
at net.hasor.core.container.BeanContainer.access$000(BeanContainer.java:42) ~[classes/:na]
at net.hasor.core.container.BeanContainer$1.get(BeanContainer.java:144) ~[classes/:na]
at net.hasor.core.provider.SingleProvider.get(SingleProvider.java:35) ~[classes/:na]
at net.hasor.core.container.BeanContainer.createObject(BeanContainer.java:142) ~[classes/:na]
at net.hasor.core.container.TemplateBeanBuilder.getDefaultInstance(TemplateBeanBuilder.java:88) ~[classes/:na]
at net.hasor.core.context.TemplateAppContext$1.get(TemplateAppContext.java:149) ~[classes/:na]
at net.hasor.core.context.TemplateAppContext.getInstance(TemplateAppContext.java:98) ~[classes/:na]
at net.hasor.core.container.TemplateBeanBuilder.injInject(TemplateBeanBuilder.java:249) ~[classes/:na]
at net.hasor.core.container.TemplateBeanBuilder.injectObject(TemplateBeanBuilder.java:232) ~[classes/:na]
at net.hasor.core.container.TemplateBeanBuilder.doInject(TemplateBeanBuilder.java:176) ~[classes/:na]
at net.hasor.core.container.TemplateBeanBuilder.createObject(TemplateBeanBuilder.java:149) ~[classes/:na]
at net.hasor.core.container.BeanContainer.callSuperCreateObject(BeanContainer.java:156) ~[classes/:na]
at net.hasor.core.container.BeanContainer.createObject(BeanContainer.java:148) ~[classes/:na]
at net.hasor.core.container.TemplateBeanBuilder.getDefaultInstance(TemplateBeanBuilder.java:88) ~[classes/:na]
at net.hasor.core.context.TemplateAppContext$1.get(TemplateAppContext.java:149) ~[classes/:na]
at net.hasor.core.context.TemplateAppContext.getInstance(TemplateAppContext.java:98) ~[classes/:na]
at net.hasor.core.provider.ClassAwareProvider.get(ClassAwareProvider.java:40) ~[classes/:na]
at net.hasor.rsf.rpc.caller.remote.RsfInvokeFilterChain.doFilter(RsfInvokeFilterChain.java:40) ~[classes/:na]
at net.hasor.rsf.rpc.caller.RsfFilterHandler.doFilter(RsfFilterHandler.java:43) ~[classes/:na]
at net.hasor.rsf.filters.online.OnlineRsfFilter.doFilter(OnlineRsfFilter.java:37) ~[classes/:na]
at net.hasor.rsf.rpc.caller.RsfFilterHandler.doFilter(RsfFilterHandler.java:41) ~[classes/:na]
at net.hasor.rsf.filters.thread.LocalWarpFilter.doFilter(LocalWarpFilter.java:32) ~[classes/:na]
at net.hasor.rsf.rpc.caller.RsfFilterHandler.doFilter(RsfFilterHandler.java:41) ~[classes/:na]
at net.hasor.rsf.filters.local.LocalPref.doFilter(LocalPref.java:49) ~[classes/:na]
at net.hasor.rsf.rpc.caller.RsfFilterHandler.doFilter(RsfFilterHandler.java:41) ~[classes/:na]
at net.hasor.rsf.filters.trace.TraceFilter.doFilter(TraceFilter.java:40) ~[classes/:na]
at net.hasor.rsf.rpc.caller.RsfFilterHandler.doFilter(RsfFilterHandler.java:41) ~[classes/:na]
at net.hasor.rsf.rpc.caller.remote.InvokerProcessing.run(InvokerProcessing.java:152) ~[classes/:na]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_74]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_74]
at java.lang.Thread.run(Thread.java:745) [na:1.8.0_74]
Caused by: java.lang.VerifyError: Inconsistent stackmap frames at branch target 101
Exception Details:
Location:
net/hasor/website/manager/UserManager$A_19.loginUpdate(Lnet/hasor/website/domain/UserDO;Ljava/lang/String;)V @101: new
Reason:
Type top (current frame, locals[3]) is not assignable to 'java/lang/Throwable' (stack map, locals[3])
Current Frame:
bci: @92
flags: { }
locals: { 'net/hasor/website/manager/UserManager$A_19', 'net/hasor/website/domain/UserDO', 'java/lang/String', top, top, 'java/lang/Throwable' }
stack: { integer }
Stackmap Frame:
bci: @101
flags: { }
locals: { 'net/hasor/website/manager/UserManager$A_19', 'net/hasor/website/domain/UserDO', 'java/lang/String', 'java/lang/Throwable' }
stack: { }
Bytecode:
0x0000000: 1002 bd00 0659 1000 1208 5359 1001 120a
0x0000010: 533a 0410 02bd 000c 5910 002b 5359 1001
0x0000020: 2c53 3a05 2ab6 0012 1213 1904 b600 173a
0x0000030: 06bb 0019 5919 062a 1905 b700 1d3a 07bb
0x0000040: 001f 5912 2119 0619 07b7 0024 b600 283a
0x0000050: 0819 0857 b13a 0519 05c1 002a 9900 0919
0x0000060: 05c0 002a bfbb 002a 5919 05b7 002d bf
Exception Handler Table:
bci [0, 83] => handler: 85
Stackmap Table:
same_locals_1_stack_item_extended(@85,Object[#4])
append_frame(@101,Object[#4])
at java.lang.Class.getDeclaredConstructors0(Native Method) ~[na:1.8.0_74]
at java.lang.Class.privateGetDeclaredConstructors(Class.java:2671) ~[na:1.8.0_74]
at java.lang.Class.getConstructor0(Class.java:3075) ~[na:1.8.0_74]
at java.lang.Class.getConstructor(Class.java:1825) ~[na:1.8.0_74]
at net.hasor.core.container.TemplateBeanBuilder.createObject(TemplateBeanBuilder.java:142) ~[classes/:na]
... 44 common frames omitted
Process finished with exit code 137 (interrupted by signal 9: SIGKILL)
----------
Hasor 的 Aop 功能是通过 asm 进行动态代理,每个被代理的方法会用如下方式生成。一般情况下这个生成的类是在内存中的,本地磁盘是看不到它的。为了排查框架问题,在 Hasor 3.1.0 版本之后添加了 “WORK_MODE” 环境变量参数,将其设置为 debug。
之后所有被 Hasor 动态代理的类都会 把生成的 class 保存到 work 目录下的 temp 目录中了。
现在看一下 Hasor aop 动态代理方法的全貌把。这个asm 生成动态类的 java 反编译,目测生成的代码没有什么异常。
----------
既然代码反编译成 java 源文件看不出端倪,那我们就直接 “javap -p -c ”看一下字节码指令上不同的地方。javap 反编译,生成的代码(右侧)和java8下编译的代码(左侧)。经过字节码反编译似乎看出了端倪,难道是因为 return 指令强制后置的问题?
----------
既然出现问题的代码在 catch 块中,那就把 异常抛出的生成代码简化一下。把上面的代码封装到一个工具类里然后去生成一个更为简单的 throw 语句,如下:
问题解决。
----------
总结一下:虽然最后引发原因的异常指令暂时没找到,但是问题搞定了。最后原因定位在生成的 if 代码问题上。以后有时间在 深入一下 jvm 源码看看 jdk8 加了什么新东西。
----------
最后更新
问题在大约 1 年前解决了,近看看到这个 blog 顺手更新一下。 问题是字节码生成指令结果不够严谨。 和 jdk 版本无关系,需要加入 -noverify 参数是因为,不严谨的代码能够运行但是有安全风险,因此才会要加参数来压制。
目前 Hasor 的 字节码增强部分已经 完美运行在各个 jvm 平台之上。
在生成字节码的时候要额外注意下面几项:
- double、long 两个类型作为入参时候,方法入参上这两种类型的 变量表顺序是要额外 +1 的
- 不要故意忽略方法变量表的输出 “visitLocalVariable” 虽然可以忽略但是会遇到编译器报错,这个报错可以用过 -noverify 压制,但毕竟是不严谨的。
来源:oschina
链接:https://my.oschina.net/u/1166271/blog/839151