zoukankan      html  css  js  c++  java
  • 运行时常量池中的符号引用/String.intern() /ldc指令

    运行时常量池,之前放在方法区(永久代)中,1.8之后被转移到元空间,放到了native memory中。

    具体的数据结构是:(看对象的内存布局,句柄访问还是对象头中保存指向类的元数据的指针,这里以对象头markword之后保存指向元数据指针为例)对象有一个指向类元数据的指针,指向的这个数据结构InstanceClass,InstanceKlass有一个指针指向一个constantPool数据结构(运行时常量池),这个数据结构是一个数组,数组里面元素的排列方式和class文件中是一样的(从1号常量到N号常量),只不过值有变化,7-18里面保存的是数字,根据规则拆开指向的是1-6类型的序号,而1-6类型保存的指向symbol结构体的指针,在class文件中,1-6指向的内容是class文件单独的,而在运行时常量池中,指向的symbol结构体是可以共享的,能做到这一点是因为在引用symbol结构体之前,要经过一个hashTable存取(这个和我们从hashmap中get push的原理差不多),这个hashTable叫symbolTable,存放在元空间,而每个symbol的结构体也存放在元空间。

    在ldc命令(以类型1的utf-8为例)中,如果ldc后面的两个字节指向的符号引用没有被解析过,指向的必然是symbol结构体在自己的class对应的运行时常量池中的序号,那么需要首先去StringTable(和symbolTable一样的一个hashTable,存放在元空间中,保存着指向堆中的String对象的引用)找和symbol结构体相等的String对象,如果找到,把自己后面两个字节保存这个String对象的引用,然后把这个string对象的引用放入栈顶。如果没找到,从刚才说的symbol结构体中(下面的红色字体)解析出String对象(这里要先创建一个char数组对象,棕色字体),并放到字符串常量池(StringTable)中(粉色字体,intern方法),然后两个字节替换成引用,入栈。

    而String.intern()方法是根据一个String对象去StringTable中找,找到了,方法返回里面对象的引用,找不到,放进去,返回引用。所以返回值是不是原String看之前有没有

    oop StringTable::intern(Symbol* symbol, TRAPS) {
      if (symbol == NULL) return NULL;
      ResourceMark rm(THREAD);
      int length;
      jchar* chars = symbol->as_unicode(length);  // 从 Symbol 中解析出字符串字面量
      Handle string;
      oop result = intern(string, chars, length, CHECK_NULL); // 调用又一个同名方法
      return result;
    }

     字符串拼接,字节码分析可以见这篇文章:https://www.cnblogs.com/Kidezyq/p/8040338.html

    String a = new String("a");
    String b = new String("a");

    这一段代码中a和b是不相等的

    String a = "a";
    String b = "a";

    这第二段代码中a和b是相等的

    先看第二段代码,反编译成字节码是这样的:

    可以看到,第0行,ldc根据a这个字符串,新建了一个String对象,并把地址存入1号本地变量位,第3行,再次根据a这个字符串创建String对象,这时候发现字符串常量池中有了,直接返回引用,并在第5行存到2号本地变量位,之后如果比较1和2变量的时候,肯定是相等的。

    再看第一段代码,反编译成字节码是这样的:

    可以看到,先是new方法新建一个String对象,复制一份到栈顶,再用ldc生成一个String对象到栈顶,第6行是调用string的构造方法,给栈底的String对象赋初始值。可见虽然两个ldc命令返回同一个String对象,但是a和b并不指向ldc返回的这个String对象,而是指向新的两个对象,而这两个对象的value值都是ldc返回值的value值。

  • 相关阅读:
    CSS盒子模型
    getContextPath、getServletPath、getRequestURI、request.getRealPath的区别
    MYSQL中的CASE WHEN END AS
    单点登录的精华总结
    git&github
    June 21st 2017 Week 25th Wednesday
    June 20th 2017 Week 25th Tuesday
    June 19th 2017 Week 25th Monday
    June 18th 2017 Week 25th Sunday
    June 17th 2017 Week 24th Saturday
  • 原文地址:https://www.cnblogs.com/chuliang/p/8447698.html
Copyright © 2011-2022 走看看