我使用ASM库生成字节码,方法的“最大堆栈大小”将自动计算。在运行期间,我发现此值(最大堆栈大小)不正确。
我的源代码是:
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
....
MethodType initType = MethodType.methodType(void.class, clsList);
mv = cw.visitMethod(ACC_PUBLIC, "<init>", initType.toMethodDescriptorString(), null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/invoke/BaseTemplate", "<init>", "()V", false);
for(int i=0; i< list.size(); i++){
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 1+i);
mv.visitFieldInsn(PUTFIELD, className, list.get(i).name(), Utils.getFieldDesc(list.get(i).type()));
}
mv.visitInsn(RETURN);
//mv.visitMaxs(2, 4); //Verify succeeds if uncomment this line.
mv.visitEnd();
....
//Verify generated code before class loading..
PrintWriter pw = new PrintWriter(System.out);
CheckClassAdapter.verify(new ClassReader(cw.toByteArray()), true, pw);
Class<?> expClass =defineClass(..);
上面的代码将生成字节码:
Classfile /C:/temp/TGWD.class
Last modified Mar 11, 2015; size 403 bytes
MD5 checksum f58b96ad4cb0bc9e62f2ae5e11e63e90
public class TGWD extends java.lang.invoke.BaseTemplate
minor version: 0
major version: 51
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Utf8 TGWD
#2 = Class #1 // TGWD
#3 = Utf8 java/lang/invoke/BaseTemplate
#4 = Class #3 // java/lang/invoke/BaseTemplate
#5 = Utf8 guard
#6 = Utf8 Ljava/lang/invoke/MethodHandle;
#7 = Utf8 trueTarget
#8 = Utf8 falseTarget
#9 = Utf8 <init>
#10 = Utf8 (Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;)V
#11 = Utf8 ()V
#12 = NameAndType #9:#11 // "<init>":()V
#13 = Methodref #4.#12 // java/lang/invoke/BaseTemplate."<init>":()V
#14 = NameAndType #5:#6 // guard:Ljava/lang/invoke/MethodHandle;
#15 = Fieldref #2.#14 // TGWD.guard:Ljava/lang/invoke/MethodHandle;
#16 = NameAndType #7:#6 // trueTarget:Ljava/lang/invoke/MethodHandle;
#17 = Fieldref #2.#16 // TGWD.trueTarget:Ljava/lang/invoke/MethodHandle;
#18 = NameAndType #8:#6 // falseTarget:Ljava/lang/invoke/MethodHandle;
#19 = Fieldref #2.#18 // TGWD.falseTarget:Ljava/lang/invoke/MethodHandle;
#20 = Utf8 eval
#21 = Utf8 Code
{
final java.lang.invoke.MethodHandle guard;
flags: ACC_FINAL
final java.lang.invoke.MethodHandle trueTarget;
flags: ACC_FINAL
final java.lang.invoke.MethodHandle falseTarget;
flags: ACC_FINAL
public TGWD(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle);
flags: ACC_PUBLIC
Code:
stack=0, locals=4, args_size=4
0: aload_0
1: invokespecial #13 // Method java/lang/invoke/BaseTemplate."<init>":()V
4: aload_0
5: aload_1
6: putfield #15 // Field guard:Ljava/lang/invoke/MethodHandle;
9: aload_0
10: aload_2
11: putfield #17 // Field trueTarget:Ljava/lang/invoke/MethodHandle;
14: aload_0
15: aload_3
16: putfield #19 // Field falseTarget:Ljava/lang/invoke/MethodHandle;
19: return
public void eval();
flags: ACC_PUBLIC
Code:
stack=0, locals=1, args_size=1
0: return
}
字节码报告错误:
org.objectweb.asm.tree.analysis.AnalyzerException: Error at instruction 0: Insufficient maximum stack size.
at org.objectweb.asm.tree.analysis.Analyzer.analyze(Unknown Source)
at org.objectweb.asm.util.CheckClassAdapter.verify(Unknown Source)
at org.objectweb.asm.util.CheckClassAdapter.verify(Unknown Source)
因为构造方法:stack = 0,locals = 4,args_size = 4
正确的堆栈大小为2。
即使设置了ClassWriter(COMPUTE_MAX+COMPUTE_STACK),仍有另一个线程ASM(来自ObjectWeb)无法正确计算MaxStack,这表明如果其他地方的字节码无效,则可能会错误地计算最大堆栈大小。
所以对我来说,问题是:
您不能忽略对的呼叫visitMax
。从以下文档中ClassWriter.COMPUTE_MAXS
:
如果该标志被设置,则自变量visitMaxs所述的方法MethodVisitor中由返回visitMethod方法将被忽略,并且从签名和每个方法的字节码自动计算。
换句话说,当您指定标志时,您可以传入任何您想要的内容,例如,调用visitMax(-1,-1)
以强调您没有提供实际值,但是您仍然必须调用该方法来触发正确值的计算。
顺便说一句,由于您创建的是版本的类文件,因此51
您应该指定,COMPUTE_FRAMES
因为我怀疑要StackMapTable
手动创建属性。请注意,这COMPUTE_FRAMES
暗示着COMPUTE_MAXS
行为。
问题内容: 我正在使用Direct Web Remoting(DWR)JavaScript库文件,并且仅在Safari(台式机和iPad)中出现错误 它说 超出最大呼叫堆栈大小。 该错误的确切含义是什么,它会完全停止处理吗? 也适用于浏览器的所有修复程序(实际上在上, JS:执行超出超时 我假设是相同的调用堆栈问题) 问题答案: 这意味着在代码的某处,你正在调用一个函数,该函数又调用另一个函数,依
问题内容: 我正在运行一个用Java在Eclipse中编写的程序。对于很大的输入,该程序具有很深的递归级别。对于较小的输入,程序运行正常,但是在给出较大的输入时,出现以下错误: 可以通过增加Java堆栈大小来解决此问题,如果可以,那么如何在Eclipse中做到这一点? 更新: @乔恩·斯基特 该代码递归地遍历解析树以建立数据结构。因此,例如,代码将使用解析树中的一个节点来做一些工作,并在该节点的两
我得到了这个StackOverFlow错误,我完全理解,但问题是我不是在处理大数据,那么这个错误是怎么产生的呢? 我有一个活动,框架布局,一个片段,3个选项。 在片段中,当你点击其中一个选项时,它会重新创建片段并放入随机数,最大值是,所以它没那么大,当用户快速点击导致溢出的选项时会发生此错误。 这是生成代码,关于“增强”它有什么想法吗?我不知道这段代码是否是一种不好的记忆使用方法。
我有一个与我的Ng2项目的3-4天的问题。 @angular/cli:1.0。0-rc。2 节点:6.9。2 操作系统:win32 x64 @角度/普通:2.4。9 @角度/编译器:2.4。9 @角度/核心:2.4。9 @角度/形状:2.4。9 @angular/http:2.4。9 @角度/平台浏览器:2.4。9 @角度/平台浏览器动态:2.4。9 @角度/路由器:3.4。9 @angular/
问题内容: 当我运行我的代码时,Node.js引发由过多的递归调用引起的异常。我试图将Node.js堆栈大小增加,但是Node.js崩溃而没有任何错误消息。当我不使用sudo再次运行此命令时,Node.js将输出。是否有可能在不删除递归调用的情况下解决此问题? 问题答案: 您应该将递归函数调用包装到 , 要么 函数使node.js有机会清除堆栈。如果您不这样做,并且有很多循环没有任何 真正的 异步
问题内容: 我想这意味着有一个循环引用,但是对于我的一生,我无法猜测如何解决它。 有人有主意吗? http://plnkr.co/edit/aNcBcU?p=预览 检查Chrome中的调试控制台(例如),您将看到错误。冒犯的行是 通过以下方式在控制器上对scope.map进行“ $ watched” 问题答案: 这是因为您要比较对象是否相等,而不是参考。将您的声明更改为此: