精华内容
下载资源
问答
  • welcome to my blog 根据《深入理解Java虚拟机》和网上搜索资料总结一下这三个区别 ...常量池中主要存放两大类常量: 字面量(Literal)和符号引用(Symbolic References) 字面量比较接近于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;
        }
    }
    
    展开全文
  • 字符串常量池存的是字符串常量和堆内的字符串对象的引用。 静态常量池(class文件常量池) 用于存放编译器生成的各种字面量(Literal)和符号引用(Symbolic References)。 字面量:文本字符串int long 等基本类型....

    字符串常量池(String Pool)

    • java6:
      • 存在于永久代中。
      • 字符串常量池保存的是字符串常量。
    • java7:
      • 转移到了堆中。
      • 字符串常量池存的是字符串常量和堆内的字符串对象的引用。

    静态常量池(class文件常量池)

    • 用于存放编译器生成的各种字面量(Literal)和符号引用(Symbolic References)。
      • 字面量:文本字符串int long 等基本类型和被声明为final的常量值等。

      • 符号引用:是一组符号来描述所引用的目标,符号可以是任何形式的字面量一般包含以下三种:

        1. 类和接口的全限定名:例如对于String这个类,它的全限定名就是java/lang/String。
        2. 字段的名称和描述符:这里的字段就是类或者接口中声明的变量。
        3. 方法的名称和描述符:这里的描述符是方法的参数类型+返回值类型。
      • 静态常量池其实就是class文件里的一部分内容。以下图片是编译后的class文件。
        在这里插入图片描述

    运行时常量池

    • 当类加载到内存中后,jvm就会将静态常量池中的内容存放到运行时常量池中。
    • 运行时常量池中的字符串在从静态常量池加载时
      1. 会先去String Poll中查询此此字符串在String Poll中的引用
      2. 如果没有则在String Poll中创建此字符串然后返回其引用
      3. 用返回的引用替换运行时常量池的字符串
    • 运行时常量池是全局共享的,多个类共用一个运行时常量池。并且class文件中常量池多个相同的字符串在运行时常量池只会存在一份

    String.intern() 方法

    • jdk 6中:在String Poll中创建字符串常量。

    • jdk 7中: 如果字符串在堆中已经存在把堆得引用存入String Poll,不存在则在String Poll中创建字符串常量。

      • String str="";双引号会在String poll中直接创建。
      • String.valueOf(1);不会在String poll中直接创建。
      • (new Long(3l)).toString();不会在String poll中直接创建。
    String s = new String("a");
    System.out.println(s.intern() == s);// false
    // 解析:此时创建了两个对象 1,"a"在字符串常量池中 2,s 在堆中new了新的字符串对象。
    // 两个对象一个在String Poll中一个在堆中所以是false
    
    String s = new String("a") + new String("b");// 1
    System.out.println(s.intern() == s);//2
    // true
            
    // 解析:第1行代码创建了5个对象  字符串常量池中的:"a"和"b" 堆中的:new String("a")和new String("b")和s
    // 第二行代码调用s.intern() 由于字符串常量池中并不存在"ab"所以会把s的引用放入String Poll 并返回这个引用 所以会返回true
    
    展开全文
  • 类常量池 诞生时间:编译时 所处区域:堆(类常量池存在Class文件,一个Class文件对应一个...所处区域:本地内存(每个class都有一个运行时常量池运行时常量池存在元空间) 储存内容:class文件元信息描述,编...

    类常量池

    诞生时间:编译时
    所处区域:堆(类常量池存在Class文件中,一个Class文件对应一个类常量池)
    储存内容:符号引用和字面量。

    字符串常量池

    诞生时间:编译时
    所处区域:堆
    储存内容:堆内的字符串对象的引用和字符串常量。

    运行时常量池

    诞生时间:当类加载到内存中后
    所处区域:本地内存(每个class都加载后常量池的数据被汇总到运行时常量池,运行时常量池存在元空间中)
    储存内容:class文件元信息描述,编译后的代码数据,引用类型数据(类经过解析后会把符号引用替换为直接引用,解析的过程会去查询字符串常量池,以保证运行时常量池所引用的字符串与全局字符串池中所引用的是一致的)。

    展开全文
  • 题目考查的为Java中的字符串常量池和JVM运行时数据区的相关概念。"abc"为字面量对象,其存储在堆内存中。而字符串常量池则存储的是字符串对象的一个引用。Java中的字符串常量池Java中字符串对象创建有两种形式,一种...

    最近做到一个题目:

    问题:String str = new String(“abc”),“abc”在内存中是怎么分配的?    答案是:堆,字符串常量区。

    题目考查的为Java中的字符串常量池和JVM运行时数据区的相关概念。"abc"为字面量对象,其存储在堆内存中。而字符串常量池则存储的是字符串对象的一个引用。

    Java中的字符串常量池

    Java中字符串对象创建有两种形式,一种为字面量形式,如String str = "droid";,另一种就是使用new这种标准的构造对象的方法,如String str = new String("droid");,这两种方式我们在代码编写时都经常使用,尤其是字面量的方式。然而这两种实现其实存在着一些性能和内存占用的差别。这一切都是源于JVM为了减少字符串对象的重复创建,其维护了一个特殊的内存,这段内存被成为字符串常量池或者字符串字面量池。

    工作原理

    当代码中出现字面量形式创建字符串对象时,JVM首先会对这个字面量进行检查,如果字符串常量池中存在相同内容的字符串对象的引用,则将这个引用返回,否则新的字符串对象被创建,然后将这个引用放入字符串常量池,并返回该引用。

    举例说明

    字面量创建形式

    String str1="droid";

    JVM检测这个字面量,这里我们认为没有内容为droid的对象存在。JVM通过字符串常量池查找不到内容为droid的字符串对象存在,那么会创建这个字符串对象,然后将刚创建的对象的引用放入到字符串常量池中,并且将引用返回给变量str1。

    如果接下来有这样一段代码:

    String str2="droid";

    同样JVM还是要检测这个字面量,JVM通过查找字符串常量池,发现内容为”droid”字符串对象存在,于是将已经存在的字符串对象的引用返回给变量str2。注意这里不会重新创建新的字符串对象。

    验证是否为str1和str2是否指向同一对象,我们可以通过这段代码

    System.out.println(str1==str2);

    输出:True.

    使用new创建

    String str3=new String("droid");

    当我们使用了new来构造字符串对象的时候,不管字符串常量池中有没有相同内容的对象的引用,新的字符串对象都会创建。因此我们使用下面代码测试一下,

    System.out.println(str1==str3);

    结果返回:False 表明这两个变量指向的为不同的对象.

    intern

    对于上面使用new创建的字符串对象,如果想将这个对象的引用加入到字符串常量池,可以使用intern方法。

    调用intern后,首先检查字符串常量池中是否有该对象的引用,如果存在,则将这个引用返回给变量,否则将引用加入并返回给变量。

    String str4=str3.intern();

    System.out.println(str4==str1);

    输出结果为True。

    疑难问题

    前提条件?

    字符串常量池实现的前提条件就是Java中String对象是不可变的,这样可以安全保证多个变量共享同一个对象。如果Java中的String对象可变的话,一个引用操作改变了对象的值,那么其他的变量也会受到影响,显然这样是不合理的。

    引用 or 对象

    字符串常量池中存放的是引用还是对象,这个问题是最常见的。字符串常量池存放的是对象引用,不是对象。在Java中,对象都创建在堆内存中。

    关于验证请参考原文。

    优缺点

    字符串常量池的好处就是减少相同内容字符串的创建,节省内存空间。

    如果硬要说弊端的话,就是牺牲了CPU计算时间来换空间。CPU计算时间主要用于在字符串常量池中查找是否有内容相同对象的引用。不过其内部实现为HashTable,所以计算成本较低。

    GC回收?

    因为字符串常量池中持有了共享的字符串对象的引用,这就是说是不是会导致这些对象无法回收?

    首先问题中共享的对象一般情况下都比较小。据我查证了解,在早期的版本中确实存在这样的问题,但是随着弱引用的引入,目前这个问题应该没有了。

    intern使用?

    关于使用intern的前提就是你清楚自己确实需要使用。比如,我们这里有一份上百万的记录,其中记录的某个值多次为美国加利福尼亚州,我们不想创建上百万条这样的字符串对象,我们可以使用intern只在内存中保留一份即可。关于intern更深入的了解请参考深入解析String#intern。

    总有例外?

    你知道下面的代码,会创建几个字符串对象,在字符串常量池中保存几个引用么?

    String test = "a" + "b" + "c";

    答案是只创建了一个对象,在常量池中也只保存一个引用。我们使用javap反编译看一下即可得知。

    17:02 $ javap -c TestInternedPoolGC

    Compiled from "TestInternedPoolGC.java"

    public class TestInternedPoolGC extends java.lang.Object{

    public TestInternedPoolGC();

    Code:

    0:  aload_0

    1:  invokespecial    #1; //Method java/lang/Object."":()V

    4:  return

    public static void main(java.lang.String[])   throws java.lang.Exception;

    Code:

    0:  ldc  #2; //String abc

    2:  astore_1

    3:  return

    看到了么,实际上在编译期间,已经将这三个字面量合成了一个。这样做实际上是一种优化,避免了创建多余的字符串对象,也没有发生字符串拼接问题。关于字符串拼接,可以查看Java细节:字符串的拼接。

    Java中的堆和栈的区别

    当一个人开始学习Java或者其他编程语言的时候,会接触到堆和栈,由于一开始没有明确清晰的说明解释,很多人会产生很多疑问,什么是堆,什么是栈,堆和栈有什么区别?更糟糕的是,Java中存在栈这样一个后进先出(Last In First Out)的顺序的数据结构,这就是java.util.Stack。这种情况下,不免让很多人更加费解前面的问题。事实上,堆和栈都是内存中的一部分,有着不同的作用,而且一个程序需要在这片区域上分配内存。众所周知,所有的Java程序都运行在JVM虚拟机内部,我们这里介绍的自然是JVM(虚拟)内存中的堆和栈。

    区别

    java中堆和栈的区别自然是面试中的常见问题,下面几点就是其具体的区别

    各司其职

    最主要的区别就是栈内存用来存储局部变量和方法调用。

    而堆内存用来存储Java中的对象。无论是成员变量,局部变量,还是类变量,它们指向的对象都存储在堆内存中。

    独有还是共享

    栈内存归属于单个线程,每个线程都会有一个栈内存,其存储的变量只能在其所属线程中可见,即栈内存可以理解成线程的私有内存。

    而堆内存中的对象对所有线程可见。堆内存中的对象可以被所有线程访问。

    异常错误

    如果栈内存没有可用的空间存储方法调用和局部变量,JVM会抛出java.lang.StackOverFlowError。

    而如果是堆内存没有可用的空间存储生成的对象,JVM会抛出java.lang.OutOfMemoryError。

    空间大小

    栈的内存要远远小于堆内存,如果你使用递归的话,那么你的栈很快就会充满。如果递归没有及时跳出,很可能发生StackOverFlowError问题。

    你可以通过-Xss选项设置栈内存的大小。-Xms选项可以设置堆的开始时的大小,-Xmx选项可以设置堆的最大值。

    这就是Java中堆和栈的区别。理解好这个问题的话,可以对你解决开发中的问题,分析堆内存和栈内存使用,甚至性能调优都有帮助。

    译文信息

    展开全文
  • 前言 本文主要用于记录和分享一下博主在解决如题问题时,从各种途径所查询到个人认为比较可信相关资料,以及他人或个人得出一些结论。...顾名思义,即用于存放字符串常量的运行时内存结构,其底层实现为一种
  • 常量池分类Java中常池可以分为Class常量池、运行时常量池字符串常量池。1. Class文件常量池在Class文件除了有类版本、字段、方法、接口等描述信息外,还有一项信息是常量池(Constant Pool Table),用于...
  • 运行时常量池(The Run-Time Constant Pool) String常量池   类文件常量池 ---- 存在于Class文件 所处区域:堆 诞生时间:编译时 内容概要:符号引用和字面量 class常量池是在编译时候每个class都...
  • 1、常量 常量在java中就值是一般的字面量,比如字符串,整数,浮点数等等数据。简单理解java中什么叫常量 2、常量池,也叫静态常量池,说常量池一定要指明是编译器生产
  • 最近在看jvm,发现了好多常量池,搞不清区别,查看了好多篇博客,简单总结一下。 Class常量池 我们写每一个Java类被编译后,就会形成一份class文件;class文件除了包含类版本、字段、方法...运行时常量池 Class常
  • 当代码出现字面量形式创建字符串对象,JVM首先会对这个字面量进行检查,如果字符串常量池中存在相同内容的字符串对象的引用,则将这个引用返回,否则新的字符串对象被创建,然后将这个引用放入字符串常量池,并...
  • java文件经过编译期生成class文件【描述信息和class常量池】,class文件再经过加载到内存【对应相关的运行时常量池字符串常量池】,供java应用程序使用。 一、基本介绍 一个class文件包括信息: 1、class常量...
  • 运行时常量池(The Run-Time Constant Pool) String常量池   类文件常量池 ---- 存在于Class文件 所处区域:堆 诞生时间:编译时 内容概要:符号引用和字面量 class常量池是在编译时候每个class都有...
  • 概念字符串常量池(String Pool)保存所欲字符串字面量(literal strings),这些字面量在编译时期就确定,不仅如此,还可以使用Stringintern()方法在运行时添加到常量池中常量池的使用主要有两种方法...
  • 当代码出现字面量形式创建字符串对象,JVM首先会对这个字面量进行检查,如果字符串常量池中存在相同内容的字符串对象的引用,则将这个引用返回,否则新的字符串对象被创建,然后将这个引用放入字符串常量池,并...
  • class文件除了包含类版本、字段、方法、接口等描述信息外,还有一项信息就是常量池(constant pool table),用于存放编译器生成各种字面量(Literal)和符号引用(Symbolic References); 每个class文件都有一个...
  • Java中的字符串常量池

    2017-07-25 21:07:00
    题目考查的为Java中的字符串常量池和JVM运行时数据区的相关概念。"abc"为字面量对象,其存储在堆内存中。而字符串常量池则存储的是字符串对象的一个引用。 Java中的字符串常量池 Java中字符串对象创建有两种形式...
  • 题目考查的为Java中的字符串常量池和JVM运行时数据区的相关概念。"abc"为字面量对象,其存储在堆内存中。而字符串常量池则存储的是字符串对象的一个引用。Java中的字符串常量池Java中字符串对象创建有两种形式,一种...
  • Java 字符串常量池

    2020-01-07 22:53:44
    1. 概述 1.1 Java 中有几种不同的常量池 class常量池 我们写到每一个 Java 类被编译后,就会形成...运行时常量池 方法区的一部分 用于存放class常量池中的内容 字符串常量池 JDK6.0及之前,字符串常量池存放在...
  • Java中的常量池,实际上分为两种形态:静态常量池和运行时常量池。 所谓静态常量池,即*.class文件中的常量池,class文件中的常量池不仅仅包含字符串(数字)字面量,还包含类、方法的信息,占用class文件绝大部分...
  • Java中的常量池,实际上分为两种形态:静态常量池和运行时常量池。1)所谓静态常量池,即*.class文件中的常量池,class文件中的常量池不仅仅包含字符串(数字)字面量,还包含类、方法的信息,占用class文件绝大部分...
  • 当代码出现字面量形式创建字符串对象,JVM首先会对这个字面量进行检查,如果字符串常量池中存在相同内容的字符串对象的引用,则将这个引用返回,否则新的字符串对象被创建,然后将这个引用放入字符串常量池,并...
  • Java文件被编译成 Class文件,Class文件除了包含类版本、字段、方法、接口等描述信息外,还有一项就是常量池常量池是当Class文件被Java虚拟机加载进来后存放在方法区 各种字面量 (Literal)和 符号引用 。...
  • Java常量池(静态常量池与运行时常量池

    万次阅读 热门讨论 2018-03-02 11:12:50
    Java中的常量池,实际上分为两种形态:静态常量池和运行时常量池。 1)所谓静态常量池,即*.class文件中的常量池,class文件中的常量池不仅仅包含字符串(数字)字面量,还包含类、方法的信息,占用class文件绝大部分...
  • 文章目录class常量池运行时常量池字符串常量池 java中有几种不同常量池,以下内容是对java中几种常量池介绍以及重点研究一下字符串常量池。 class常量池 我们写每一个Java类被编译后,就会形成一份class文件...
  • 理解Java字符串常量池

    2019-08-20 17:26:03
    理解Java字符串常量池 (1) 字面量创建字符串(String a=“a”)会先在字符串池中找,看是否有相等的对象,没有的话就在堆中创建,把地址驻留在字符串池;有的话则直接用池中的引用,避免重复创建对象。 (2) new...
  • 问题:String str = ...题目考查的为Java中的字符串常量池和JVM运行时数据区的相关概念。 "abc"为字面量对象,其存储在堆内存中。而字符串常量池则存储的是字符串对象的一个引用。 Java中的字符串常量池 Java中...
  • 题目考查的为Java中的字符串常量池和JVM运行时数据区的相关概念。 "abc"为字面量对象,其存储在堆内存中。而字符串常量池则存储的是字符串对象的一个引用。   Java中的字符串常量池 Java中字符串对象...

空空如也

空空如也

1 2 3 4 5 ... 13
收藏数 245
精华内容 98
关键字:

java运行时常量池字面量中的字符串

java 订阅