概述
本质上是Java语言编译后代码 存储区域,它存储每一个类的结构信息,例如:运行时常量池、成员变量、方法数据、构造方法和普通 方法的字节码指令等内容。很多语言都有类似区域。
方法区的具体实现有两种:永久代(PermGen)、元空间(Metaspace)
方法区存储的数据:
- Class信息:
- 类型信息,比如Class(com.hero.User类)
- 方法信息,比如Method(方法名称、方法参数列表、方法返回值信息)
- 字段信息,比如Field(字段类型,字段名称需要特殊设置才能保存的住)
- 类变量(静态变量)JDK1.7之后,转移到堆中存储
- 方法表(方法调用的时候) 在A类的main方法中去调用B类的method1方法,是根据B类的方法表去查找合适的方法,进行调用的。
- 运行时常量池(字符串常量池):从class中的常量池加载而来,JDK1.7之后,转移到堆中存储
- 字面量类型
- 引用类型–>内存地址
- JIT编译器编译之后的代码缓存
方法区变迁
移除永久代的工作从JDK1.7就开始了。JDK1.7中,存储在永久代的部分数据就已经转移到了Java Heap。但永久代仍存在于JDK1.7中,并没完全移除,譬如:字面量转移到了java heap;类的静态变量(class statics)转移到了java heap。
字符串常量池
** class常量池:一个class文件只有一个class常量池 **
- 字面量:数值型(int、float、long、double)、双引号引起来的字符串值等
- 符号引用:Class、Method、Field等
**运行时常量池:一个class对象有一个运行时常量池 **
同上
** 字符串常量池:全局只有一个字符串常量池 **
数据结构
StringTable, StringTable里面保存了字符串的引用 ,类似于hash表,是数组加链表,可以加速查找速度
如何查找字符串
- 根据字符串的hashcode找到对应entry
- 如果没有冲突,它可能只是一个entry
- 如何有冲突,它可能是一个entry的链表,然后Java再遍历链表,匹配引用对应的字符串
- 如果找到字符串,返回引用
- 如果找不到字符串,在使用intern()方法的时候,会将intern()方法调用者的引用放入到stringtable 中
什么字符串放入字符串常量池
- 单独使用””引号创建的字符串都是常量,编译期就已经确定存储到String Pool中。
- 使用new String(“”)创建的对象会存储到heap中,是运行期新创建的。
- 使用只包含常量的字符串连接符如”aa”+”bb”创建的也是常量,编译期就能确定已经存储到String Pool中。
- 使用包含变量的字符串连接如”aa”+s创建的对象是运行期才创建的,存储到heap中
- 运行期调用String的intern()方法可以向String Pool中动态添加对象。