Java 运行时常量池 字符串常量池 类的常量池 局部变量表

welcome to my blog

根据《深入理解Java虚拟机》和网上搜索的资料总结一下这三个的区别

类的常量池(存在于字节码文件中)

类的常量池存在于字节码文件中, 也就是.class文件. 要注意的是, 类的常量池并不在内存中, 而是字节码文件的一段内容
常量池中主要存放两大类常量: 字面量(Literal)和符号引用(Symbolic References)
字面量比较接近于Java语言层面的常量概念, 如文本字符串、使用final修饰的常量值等
符号引用则余数编译原理方面的概念,主要包括下面几类常量:

  1. 被模块到处或者开放的包(Package)
  2. 类和接口的全限定名(Fully Qualified Name)
  3. 字段的名称和描述符(Descriptor)
  4. 方法的名称和描述符
  5. 方法句柄和方法类型(Method Handle、Method Type、Invoke Dynamic)
  6. 动态调用点和动态常量(Dynamically-Computed Call Site\Dynamically-Computed Constant)
    当虚拟机做类加载时,将会从常量池获得对应的符号引用,再在类创建时或运行时解析、翻译到具体的内存地址之中

运行时常量池 (存在于方法区中)

运行时常量池位于方法区中,与类的常量池不同的地方在于,类的常量池存在于字节码文件中, 而运行时常量池存在于内存中。
JVM在类加载阶段将字节码中的常量池内容加载到方法区的运行时常量池中

类加载的准备阶段为类变量(静态变量)分配内存并设置初始值。从概念上讲,这些变量所使用的内存都应当在方法区中进行分配,但必须注意的是方法区本身是一个逻辑上的区域,在JDK7及之前,HotSpot使用永久代来实现方法区时,这些变量所使用的内存都应当在方法区中进行分配的说法是正确的;而在JDK8及以后,类变量则会随着Class对象一起存放在Java堆中,这时候“类变量在方法区”就完全是一种对逻辑概念的表述了。

运行时常量池和字节码文件中的常量池的两个区别

  1. JVM对于字节码文件每一部分(包括常量池)的格式都有严格规定,如每一个字节用于存储哪种数据都必须符合规范上的要求才会被虚拟机认可、加载和执行,但对于运行时常量池,《Java虚拟机规范》并没有做出任何细节的要求,不同的提供商实现的JVM可以按照自己的需要来实现这个内存区域,不过一般来说,除了保存字节码文件中描述的符号引用外,还会把由符号引用翻译出来的直接引用也存储在运行时常量池中。
  2. 运行时常量池相对于字节码文件常量池的另一个重要特征是具有动态性。Java语言并不要求常量一定只有编译期才能产生,也就是说,并非预置入字节码文件中常量池的内容才能进入方法区运行时常量池,运行期间也可以将新的常量放入池中,这种特性被开发人员利用的比较多的辨识String类的intern()方法。(这里我有个疑问,intern()涉及的是字符串常量池, 但字符串常量池在堆中,不在运行时常量池啊)

字符串常量池 (存在于堆中)

(这里我有个疑问)使用双引号创建的字符串, 比如说String a = “show time”;该字符串以前没有出现过, 那么这个字符串是直接放到字符串常量池中, 还是说先在堆中创建一个对象, 然后字符串常量池使用引用指向堆中的这个对象

使用String s = new String(“abc”); 创建的字符串对象直接存放到堆中, 不会主动放到字符串常量池中. 可以使用s.intern()方法让常量池使用引用指向这个对象

局部变量表(存在虚拟机栈中)

确切地说, 局部变量表存在于虚拟机栈的栈帧中
执行一个方法时, JVM会为该方法生成一个栈帧, 方法的执行和返回对应着栈帧在虚拟机栈中的的入栈和出栈;
栈帧不仅包含局部变量表, 还包含操作站,动态链接,返回地址等信息

例子: 各个变量存在的位置

public class Free {
    //位于方法区
    public static int m1 = 10;
    //位于方法区
    public static ListNode f1 = new ListNode(11);

    public static void main(String[] args) throws ClassNotFoundException {
        //位于字符串常量池
        String a1 = "abc";
        //位于堆
        String a2 = new String("efg");
        //位于堆
        ListNode f2 = new ListNode(12);
        //位于虚拟机栈
        int m2 = 10; 
    }
}

class ListNode {
    int val;
    ListNode next;

    ListNode(int val) {
        this.val = val;
    }
}

你可能感兴趣的:(Java)