精华内容
下载资源
问答
  • Java 运行时常量池

    2014-04-15 16:00:27
    大虾们说:Jvm把内存化为三个部分:1.堆 2.线程栈3方法区 ...方法区中存储了每个类型的对应的常量池。我的问题也很简单,每个类型指的是?Java八种基础数据类型 + String类型? 还是说包括了别的什么类型?
  • 最近看java虚拟机,书上说 字符串常量池在jdk1.7移除方法区了,但是运行时常量池还是方法区的一部分,那意思是不是字符串常量池 和 运行时常量池 就是两个东西 ?没有关系?那String的intern()方法是往添加到哪个池?
  • 类的常量池存在于字节码文件中, 也就是.class文件. 要注意的是, 类的常量池并不在内存中, 而是字节码文件的一段内容 常量池中主要存放两大类常量: 字面量(Literal)和符号引用(Symbolic References) 字面量比较接近于...

    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运行时常量池是JVM运行时内存模型的重要部分.我对常量池的理解大都来自于周志明大大的《深入理解Java虚拟机》, 书中对常量池有较多的描述与解释, 在内存管理, 类文件结构等部分章节中都有说明. 正如我之前...

    概述

    Java运行时常量池是JVM运行时内存模型的重要部分.我对常量池的理解大都来自于周志明大大的《深入理解Java虚拟机》, 书中对常量池有较多的描述与解释, 在内存管理, 类文件结构等部分章节中都有说明.
    正如我之前的博文–JVM内存管理对常量池描述的一样,常量池会存储字面量和符号引用,但我有个疑问:
    常量池与final修饰符的关系是怎么样的?

    Code

    public class Test{
        public static Test test = new Test();
        public final Test test2 = new Test();
    
        public final static String s1 = "1";
        public static String s2 = "2";
        public String s3 = "3";
    
        public Test(){
    
        }
    
        public static void stMethod(){
            final int sla = 10;
            final String sls = "slsv";      
        }
    
        public void tMethod(int tp){
            final int la = 11;
            final String ls = "lsv";
        }
    }

    反编译后的常量池部分代码

    public class Test
      minor version: 0
      major version: 52
      flags: ACC_PUBLIC, ACC_SUPER
    Constant pool:
       #1 = Methodref          #10.#30        // java/lang/Object."<init>":()V
       #2 = Class              #31            // Test
       #3 = Methodref          #2.#30         // Test."<init>":()V
       #4 = Fieldref           #2.#32         // Test.test2:LTest;
       #5 = String             #33            // 3
       #6 = Fieldref           #2.#34         // Test.s3:Ljava/lang/String;
       #7 = Fieldref           #2.#35         // Test.test:LTest;
       #8 = String             #36            // 2
       #9 = Fieldref           #2.#37         // Test.s2:Ljava/lang/String;
      #10 = Class              #38            // java/lang/Object
      #11 = Utf8               test
      #12 = Utf8               LTest;
      #13 = Utf8               test2
      #14 = Utf8               s1
      #15 = Utf8               Ljava/lang/String;
      #16 = Utf8               ConstantValue
      #17 = String             #39            // 1
      #18 = Utf8               s2
      #19 = Utf8               s3
      #20 = Utf8               <init>
      #21 = Utf8               ()V
      #22 = Utf8               Code
      #23 = Utf8               LineNumberTable
      #24 = Utf8               stMethod
      #25 = Utf8               tMethod
      #26 = Utf8               (I)V
      #27 = Utf8               <clinit>
      #28 = Utf8               SourceFile
      #29 = Utf8               Test.java
      #30 = NameAndType        #20:#21        // "<init>":()V
      #31 = Utf8               Test
      #32 = NameAndType        #13:#12        // test2:LTest;
      #33 = Utf8               3
      #34 = NameAndType        #19:#15        // s3:Ljava/lang/String;
      #35 = NameAndType        #11:#12        // test:LTest;
      #36 = Utf8               2
      #37 = NameAndType        #18:#15        // s2:Ljava/lang/String;
      #38 = Utf8               java/lang/Object
      #39 = Utf8               1
    

    可以看到, 常量池中并没有存储test2的值, 只存储了test2这个符号, 所以引用类型有final修饰符也不会进入常量池, 而没有final修饰符的s2, s3都进入了常量池(当然原因是他们是字面量), 可以看到是否进入常量池与final修饰符是没有关系的.

    展开全文
  • java一共实现了6中基本类型的常量池:Byte , Short,Integer,Long,Boolean,Characher。(Double和Float没有实现) 和一种String的常量池,他们在内存的方法区里 String常量池: String常量池可以储存各种不同...

    java有两种常量池:

    1静态常量池。

    静态常量池即*.class文件中的常量池,不仅仅包含字符串(数字)字面量,还包含字段,类、方法的信息(符号引用),占用class文件绝大部分空间,类加载过程中会把class文件中静态常量池的内容转移到运行时常量池,把符号引用转为直接引用。

    2运行时常量池

    java一共实现了6中基本类型的常量池:Byte , Short,Integer,Long,Boolean,Characher。(Double和Float没有实现)
    1种String的常量池。

    运行时常量池在哪:

    Java6,运行时常量池是存放在方法区中的。
    Java7及以后,将运行时常量池是存放到了堆中。

    基本类型常量池:

    和String常量池不同,基本类型的常量池只能储存 -128到127之间的常量(这也正是为什么Double和Float这种浮点数没有常量池的原因)
    当你Integer a = 127;Integer b = 127;a和b会自动拆箱,会指向常量池中创建好的127常量,所以他们a==b为true;
    但是当你Integer a = 128;Integer b = 128;超过了-128到127这个范围,它们就不会自动拆箱了,会在堆内存里面直接new对象,
    这时候他们就和普通的类对象没有区别,用等号比较的只是他们指向的内存地址而已

    String常量池:

    String常量池可以储存各种不同大小的String常量,String str1 = “abc”时,他会在常量池创建abc这个字符串常量对象,并指向它
    但你再次String str2 = “abc”时,先会去检查常量池是否有abc这个常量,由于常量池里已经有abc了,str2也直接指向同一个abc常量
    正因为他们指向的内存相等,str==str1为true,而不是因为他们的内容相等所致

    深入理解字符串常量池和intern方法强烈建议我写的另一篇文章:https://blog.csdn.net/qq_42862882/article/details/89179394

    展开全文
  • 变量的描述信息 : 变量的返回值 this 运行时常量池相对于class文件常量池的另一个重要特征是具备动态性 , java语言并不要求常量一定只有编译期才产生的 , 也就是并非预置入class文件中常量的内容才能进入方法区运行...

    存储内容

    clss文件中除了有类的版本方法 , 字段 , 接口等描述信息外 , 还有一项信息是常量池 , 用于存放编译期生成的各种字面量喝符号引用 , 这部分内容在类加载后进入方法区的运行时常量池中存放

    字面量 : 

    •   双引号引起的字符串值 , "abc" 
    •   定义为final类型的常量的值

    符号引用:

    • 类或者接口的全限定名(包括父类和所实现的接口)
    •   变量或者方法的名称
    •   变量或方法的描述信息
      • 方法的描述 : 参数个数 , 参数类型 , 方法返回类型等
      • 变量的描述信息 : 变量的返回值
    • this

    运行时常量池相对于class文件常量池的另一个重要特征是具备动态性 , java语言并不要求常量一定只有编译期才产生的 , 也就是并非预置入class文件中常量的内容才能进入方法区运行时常量池 , 运行期间也可能将新常量放入池中 , 这种特性开发人员使用较多的是String类的intern()方法。

    存储位置

    在JDk1.6及以前,运行时常量池的 方法区 一部分。

    在JDk1.7及以后,运行时常量池在 java堆 中。

    运行时与class常量池一样 , 运行时常量池也是每个类都有的一个, 但是字符串常量池只有一个局。

    字符串常量池如何存储数据

    为了提高匹配的速度 , 即更快的查找某字符串是否存在于常量池 , java在设计字符串常量池的时候 , 还搞一张stringtable , stringtable有点类似于hashtable , 保存字符串的引用

    • 在JDK6中stringtable是固定的 ,  1009长度 , 因此若放入string Pool中String 非常多 , 就会造成hash的冲突 , 导致链表过长 , 但调用String.intern()时需要到链表上一个一个找 , 从而导致性能降低 。
    • 在jdk7中stringtabkle的长度可通过一个参数指定 : -XX:StringTableSize=99999

    字符串常量池查找字符串的方式:

    • 根据字符串发hashcode找到对应entry , 若没冲突 , 它可能是一个entry , 若冲突 , 它可能一个entry链表 , 然后Java再遍历entry链表 , 匹配引用对应的字符串 。
    • 若找到字符串 , 返回引用 。若找不到字符串 , 会把字符串放到常量池 , 并把引用保存到stringtable里 。

    字符串常量池案例分析 

    public class Test {
        public void test() {
            String str1 = "abc";
            String str2 = new String("abc");
            System.out.println(str1 == str2);
            String str3 = new String("abc");
            System.out.println(str3 == str2);
            String str4 = "a" + "b";
            System.out.println(str4 == "ab");
            final String s = "a";
            String str5 = s + "b";
            System.out.println(str5 == "ab");
            String s1 = "a";
            String s2 = "b";
            String str6 = s1 + s2;
            System.out.println(str6 == "ab");
            String str7 = "abc".substring(0, 2);
            System.out.println(str7 == "ab");
            String str8 = "abc".toUpperCase();
            System.out.println(str8 == "ABC");
            String s3 = "ab";
            String s4 = "ab" + getString();
            System.out.println(s3 == s4);
            String s5 = "a";
            String s6 = "abc";
            String s7 = s5 + "bc";
            System.out.println(s6 == s7.intern());
        }
        private String getString(){
            return "c";
        }
    }
    StringIntern方法详解
            String a = "hello";
            String b = new String("hello"); 
            System.out.println(a == b);
            String c = "world"; 
            System.out.println(c.intern() == c); 
            String d = new String("mike");
            System.out.println(d.intern() == d); 
            String e = new String("jo") + new String("hn"); 
            System.out.println(e.intern() == e); 
            String f = new String("ja") + new String("va"); 
            System.out.println(f.intern() == f);

    若此题可以一题不差做对 , 接下来的内容可不用看 , 若不能并有兴趣的 , 可了解一下内容 。

    intern的作用

    intern的作用是把new出来的字符串的引用添加到stringtablejava会先计算stringhashcode,查找stringtable中是否已经有string对应的引用了,如果有返回引用(地址),然后没有把字符串的地址放到stringtable中,并返回字符串的引用(地址)。
     
    intern案例分析
     
    public static void main(String[] args) { 
        String s = new String("1"); 
        s.intern(); 
        String s2 = "1"; 
        System.out.println(s == s2); 
        String s3 = new String("1") + new String("1"); 
        s3.intern(); 
        String s4 = "11"; 
        System.out.println(s3 == s4); 
    }

    打印结果 : jdk6以下 false false         jdk7上 false true   然后将 s3.intern(); 语句下调一行,放到 String s4 = "11"; 后面。将s.intern(); 放到 String s2 = "1"; 后面。是什么结果呢?

    public static void main(String[] args) { 
        String s = new String("1"); 
        String s2 = "1"; 
        s.intern(); 
        System.out.println(s == s2); 
        String s3 = new String("1") + new String("1");
        String s4 = "11";
        s3.intern();
        System.out.println(s3 == s4);
     }

    打印结果为 : jdk6 下  false false  jdk7上 false false 

     

     

    参考资料:《深入理解Java虚拟机》

    展开全文
  • 常量被加载到运行常量池,此时并不会变成字符串对象,只有执行String s1="a"才成为对象(相当于延迟加载),成为对象后放到StringTable[]中作为key(StringTable是一个hash表,初始为空)。执行完第1行后"a"放入...
  • Java中的常量池(字符串常量池、class常量池和运行时常量池) 转载。 https://blog.csdn.net/zm13007310400/article/details/77534349 简介: 这几天在看...
  • Java中的常量池,实际上分为两种形态:静态常量池和运行时常量池。 所谓静态常量池,即*.class文件中的常量池,class文件中的常量池不仅仅包含字符串(数字)字面量,还包含类、方法的信息,占用class文件绝大部分...
  • 在JDK1.7 字符串常量池被从方法区拿到了堆中, 这里没有提到运行时常量池,也就是说字符串常量池被单独拿到堆,运行时常量池剩下的东西还在方法区, 也就是hotspot中的永久代 在JDK1.8 hotspot移除了永久代用元空间(Me....
  • 1.常量池 就是一张表,虚拟机指令根据这张常量表找到要执行的类名、方法名、参数类型、字面量等信息。...运行时常量池,常量池是*.class文件中的,当该类被加载,它的常量池信息就会放入运行时常量池,并把里面的符号
  • 1.1:字符串常量池Java内存区域的哪个位置? 在JDK6.0及之前版本,字符串常量池是放在Perm Gen区(也就是方法区)中; 在JDK7.0版本,字符串常量池被移到了堆中了。至于为什么移到堆内,大概是由于方法区的内存空间...
  • Java常量池(静态常量池与运行时常量池

    万次阅读 热门讨论 2018-03-02 11:12:50
    Java中的常量池,实际上分为两种形态:静态常量池和运行时常量池。 1)所谓静态常量池,即*.class文件中的常量池,class文件中的常量池不仅仅包含字符串(数字)字面量,还包含类、方法的信息,占用class文件绝大部分...
  • java的内存分配中,经常听到很多关于常量池的描述,我开始看的时候也是看的很模糊,网上五花八门的说法简直太多了,最后查阅各种资料,终于算是差不多理清了,很多网上说法都有问题,笔者尝试着来区分一下这几个...
  • 文章目录引入:方法区常量池概述字符串常量池class常量池运行时常量池 这里介绍 字符串常量池、class常量池 和 运行时常量池 这三个常量池的概念。 引入:方法区常量池概述 方法区包含运行时常量池、自动和方法数据...
  • 运行时常量池:当类被加载,它的常量池信息就会放入方法区的运行时常量池,并把里面的符号地址变为真实地址。 StringTable(串池)hashtable结构,不能扩容: 在jdk1.8时串池再堆区中 jdk1.7把串池移除方法区 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,236
精华内容 1,294
关键字:

java运行时常量池

java 订阅