【问题标题】:java.lang.VerifyError - When having a class with static variable that hold a reference to instance of classjava.lang.VerifyError - 当类的静态变量包含对类实例的引用时
【发布时间】:2014-01-27 14:59:46
【问题描述】:
public class Config {
    public static Ref<Config> s = new Ref<Config>(new Config());
    static class Ref<T> {
        public T r;
        public Ref(T r) {
            this.r = r;
        }
    }
    public int INTERVAL = 4000;

    public Config()
    {
    }

    public static void main(String[] args) {
        System.err.println(Config.s.r.INTERVAL);
    }
}

将此原因运行到 java.lang.VerifyError

Exception in thread "main" java.lang.VerifyError: (class: Config, method: main signature: ([Ljava/lang/String;)V) Incompatible type for getting or setting field

如果我运行这个:

System.err.println(Config.s.r);

没有抛出异常,在调试中我可以看到'Config.s.r.INTERVAL'的值

当我使用 -verbose:class 运行时,我可以看到在第一个示例中没有加载 Ref 类。在第二个示例中,加载了 Ref 类。

这是项目中唯一使用java6编译和运行的类。 问题不在 jvm 或第 3 方。

我猜这个问题是在同一行结合静态变量初始化和实例变量。

像这样运行 - 工作:

Config c = Config.s.r;
System.err.println(c.INTERVAL);

附言。代码非常复杂,它在开发环境中分为 2 个类。我只是把它限制在简短的例子中

Jdk - Java SE 6 [1.6.0_65-b14-462] 操作系统 - Mac

【问题讨论】:

  • 其中的原因都不属于这里。不涉及第三者。所有类都存在。
  • 你确定它们都是用你运行的相同版本的 Java 编译的吗? Java 字节码承诺向前兼容,但不一定向后兼容(即,在 Java 1.7 上编译的代码可能无法在 Java 1.6 上运行)。验证错误意味着字节码中的某些内容未被您的 JVM 接受,唯一可能的原因是版本控制问题、JVM 错误或有人损坏了类文件。
  • 我添加了 cmets。 10x
  • 哇!!认为自己有幸找到了一种无需进行 .class 文件交换或类似操作即可引发 VerifyError 的方法!

标签: java jvm


【解决方案1】:

我猜这是一个错误。 任何解决方法都是拆分为 2 行,如下所示:

Config c = Config.s.r;
System.err.println(c.INTERVAL);

程序集之间的差异(差异仅在主函数中): 工作的一个,打破 2 行:

public static void main(java.lang.String[]);
  Code:
   0:   getstatic   #22; //Field s:LRef;
   3:   getfield    #33; //Field Ref.r:Ljava/lang/Object;
   6:   checkcast   #1; //class Config
   9:   astore_1
   10:  getstatic   #37; //Field java/lang/System.err:Ljava/io/PrintStream;
   13:  aload_1
   14:  getfield    #27; //Field INTERVAL:I
   17:  invokevirtual   #43; //Method java/io/PrintStream.println:(I)V
   20:  return

}

坏掉的——都在一条线上:

public static void main(java.lang.String[]);
  Code:
   0:   getstatic   #33; //Field java/lang/System.err:Ljava/io/PrintStream;
   3:   getstatic   #22; //Field s:LRef;
   6:   getfield    #39; //Field Ref.r:Ljava/lang/Object;
   9:   getfield    #27; //Field INTERVAL:I
   12:  checkcast   #1; //class Config
   15:  invokevirtual   #43; //Method java/io/PrintStream.println:(I)V
   18:  return

}

在@Hot Licks 身份的帮助下,问题出在检查字段(int)而不是类的损坏版本的检查中。向 Oracle 打开错误。

【讨论】:

  • 这表明这是一个编译器错误。有更多时间工作的人可能会尝试对两个版本的代码执行javap 并查看它们的不同之处。
  • 哇!坏掉的正试图在int 上做一个checkcast!编译器是主要的。如果你喜欢这种事情,请将其作为 javac 错误提交给 Oracle。
  • 你怎么看这个?两者的checkcast不是相同的吗?这是我第一次尝试阅读这样的东西。
  • 这是一个堆栈架构。 checkcast 对压入堆栈的事物进行操作。
【解决方案2】:

翻译:

public static void main(java.lang.String[]);
  Code:
   // Fetch static field s -- place is stack location 1
   0:   getstatic   #22; //Field s:LRef;
   // Fetch instance field r using stack 1 as base -- place in stack location 1
   3:   getfield    #33; //Field Ref.r:Ljava/lang/Object;
   // Peform checkcast on stack location 1 to assure it's a "Config" -- leave stack unchanged
   6:   checkcast   #1; //class Config
   // Store stack location 1 into local variable 1.  Pop stack.
   9:   astore_1
   // Fetch static field System.err -- place in stack location 1
   10:  getstatic   #37; //Field java/lang/System.err:Ljava/io/PrintStream;
   // Fetch local variable 1 -- place in stack location 2
   13:  aload_1
   // Fetch instance field I using stack 2 as base -- place in stack location 2 
   14:  getfield    #27; //Field INTERVAL:I
   // Invoke println, using stack 1 as base, stack 2 as parm -- stack becomes empty
   17:  invokevirtual   #43; //Method java/io/PrintStream.println:(I)V
   20:  return

}

破碎的:

public static void main(java.lang.String[]);
  Code:
   // Fetch static field System.err -- place is stack location 1
   0:   getstatic   #33; //Field java/lang/System.err:Ljava/io/PrintStream;
   // Fetch static field s -- place in stack location 2
   3:   getstatic   #22; //Field s:LRef;
   // Fetch instance field r using location 2 as base -- place in stack location 2
   6:   getfield    #39; //Field Ref.r:Ljava/lang/Object;
   // --- Note that the checkcast should be here ---
   // Fetch instance field I using location 2 as base -- place in stack location 2
   9:   getfield    #27; //Field INTERVAL:I
   // Perform checkcast on location 2, to assure it's a "Config" (it isn't)
   12:  checkcast   #1; //class Config
   // Invoke println using location 1 as base, location 2 as parm.
   15:  invokevirtual   #43; //Method java/io/PrintStream.println:(I)V
   18:  return

}

【讨论】:

    猜你喜欢
    • 2011-10-09
    • 2021-09-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-25
    相关资源
    最近更新 更多