美文网首页
深入浅出JVM常量池

深入浅出JVM常量池

作者: 小杰的快乐时光 | 来源:发表于2018-08-23 07:19 被阅读0次

    常量池在JVM中分为三种:字符串常量池,运行时常量池,Class常量池
    讨论范围 JDK 1.7版本及以后

    字符串常量池(String pool)
    (1)什么是字符串常量池?
    ①字符串常量由一个个字符组成。在HotSpot虚拟机中,字符串常量池是有一个名为 StringTable 的类来实现的,StringTable是一个哈希表HashSet<String>,默认长度为1009,是被所有类共享的,因此在JVM中的实例只有一份。注意它只存储对java.lang.String实例的引用,而不存储String对象的内容,根据这个引用可以得到具体的String对象。一般我们说一个字符串进入了全局的字符串常量池其实是说在这个StringTable中保存了对它的引用,反之,如果说没有在其中就是说StringTable中没有对它的引用。

    ②在JDK1.6版本中,StringTable的长度是固定的,长度就是1009。因此如果保存的字符串常量过多,就会造成哈希冲突,导致链表过长,而链表过长的直接影响就是 当调用String.intern时性能会大幅下降(因为要一个一个找)。

    ③在JDK1.7版本中,StringTable的长度可以通过参数来指定:-XX:StringTableSize=123456

    (2)字符串常量池保存在JVM哪个区域?
    在JDK1.6及之前的版本中,字符串常量池是放在永久代(Perm Gen)中,确切来讲是永久代的方法区中。
    在JDK1.7后的版本中,字符串常量池就被移到了堆(Heap)中。之所以会被移到堆中,可能是方法区的内存空间太小了。

    (3)字符串常量池中保存的是什么?
    字符串常量池只存储引用,不存储内容!字符串不是存在字符串常量池中而是存在堆内存中,字符串池中只是该字符串的引用。
    规范里把存储Java对象的地方定义为Java heap,其它地方是不会存有Java对象的实体的(有的话那根据定于也要算Java heap的一部分)

    注:在字符串常量池中的字符串只能存在一份。

    String s1 ="JVM";
    String s2 ="JVM";
    //执行完第一段代码后,由于常量池中已经存在了"JVM"这个字符串的引用,
    //所以s2不会在常量池中申请新的空间,而是直接把已存在的字符串内存地址返回给s2。
    

    Class常量池
    (1)什么是Class常量池?
    ①在每一个Java类被编译后,会形成一个class文件。Class文件除了有类信息,字段,方法,接口等描述信息,还有一项信息是常量池(Constant Pool Table),每一个class文件都有一个class常量池。

    (2)Class常量池保存在JVM哪个区域?
    保存在堆中。

    (3)Class常量池中保存的是什么?
    用于存放编译器生成的各种字面量(Literal)和符号引用(Symbolic References);
    字面量(Literal)包括:文本字符串,八种基本类型的值,被声明为final的常量等
    符号引用(Symbolic References)包括:类和接口的全限定名(Full Qualified Name),字段的名称和描述符(Descriptor),方法的名称和描述符

    运行时常量池(Runtime Constant Pool)
    (1)什么是运行时常量池?
    运行时常量池,则是jvm虚拟机在完成类装载操作后,将class文件中的常量池载入到内存中,并保存在方法区中。 运行时常量池也就是class常量池被加载到内存之后的版本,因为每一个class文件都有一个class常量池,因此运行时常量池也是每个类都有一个。我们常说的常量池,就是指方法区中的运行时常量池。

    运行时常量池相对于Class文件常量池的重要特征是具有动态性。除了在编译器产生的常量可以进入运行时常量池外,还可以在运行期间将新的常量放入池中,比如String 的 intern方法。

    (2)运行时常量池保存在JVM哪个区域?
    位于方法区,Java虚拟机规范中将方法区描述为堆的逻辑部分,所以实际上还是在堆中。

    (3)Class常量池中保存的是什么?
    方法区的一部分。Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有常量池(Constant Pool Table),存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池。也就是说运行时常量池是class常量池的另一个版本。

    但是,这个“进入”过程,并不会直接把所有类中定义的常量全部都加载进来,而是会做个比较,如果需要加到字符串常量池中的字符串已经存在,那么就不需要再把字符串字面量加载进来了。

    推荐阅读
    https://www.zhihu.com/question/29884421
    https://www.zhihu.com/question/57109429/answer/151717241
    https://www.zhihu.com/question/55994121/answer/147296098
    https://blog.csdn.net/zm13007310400/article/details/77534349

    相关文章

      网友评论

          本文标题:深入浅出JVM常量池

          本文链接:https://www.haomeiwen.com/subject/nrzuiftx.html