jdk8中,字符串常量池位于堆内存哪个区域,有独立空间吗?

众所周知,字符串常量池从JDK1.7开始从方法区中移到了堆内存(常见的笼统说法),堆内存常规理解是划分为了新生代和老年代,JDK1.7还有堆中永久代实现方法区,字符串常量池从方法区移到堆中应该是不会继续在永久代,那么是新开辟了区域还是放入新老年代区域?

JDK8变化是移除堆中永久代,方法区采用本地内存元空间实现,字符串常量池还是在堆内存,具体在堆中哪个区域本人不太理解?

此提问经过修改,以下是个人理解,有误的地方望大佬指正,感谢!

从JDK1.7开始,字符串常量池是一个叫StringTable的哈希表结构,里面存的是缓存对象的引用地址,被缓存的字符串对象在堆内存中,会经历垃圾回收,young gc的时候,StringTable做为GC Root,被缓存对象继续存活,full gc的时候,StringTable不作为GC Root,缓存对象可以被回收,清理StringTable。个人问题其实是StringTable这个东西是开辟在哪里,比较明确是的在堆中,那么它在堆中是有一块独立空间吗?感觉应该是的。

阅读 3.5k
2 个回答

字符串常量池在堆中确实有一个独立的空间,它与堆的其他部分是分开的。字符串常量池中的对象也是在新生代中创建的,但它们通常会很快进入永久代(Java 6及更早版本)或元空间(Java 7及更高版本),这取决于JDK的版本。

在Java 6及更早版本中,字符串常量池存储在永久代中。在这种情况下,字符串常量池中的对象仍然是在新生代中创建的,但是它们可能会很快进入永久代。这是因为在Java 6中,永久代用于存储类的元数据和其他静态数据。因此,将字符串常量池存储在永久代中是有意义的,因为字符串常量通常被认为是静态的数据。

在Java 7及更高版本中,永久代已被元空间取代。元空间不是Java堆的一部分,而是使用本地内存来实现的。因此,在这种情况下,字符串常量池仍然存储在堆中,但不再是永久代,而是元空间。这意味着,字符串常量池中的对象仍然是在新生代中创建的,并且不会像在Java 6中那样很快进入永久代。

在任何情况下,字符串常量池中的对象都不会像普通对象那样被垃圾回收器回收,而是一直存活在堆中。这是因为字符串常量池中的对象是被全局引用的,因此只有在类被卸载时才会被释放。

本文参与了SegmentFault 思否面试闯关挑战赛,欢迎正在阅读的你也加入。

在学习java, 自己的笔记: https://segmentfault.com/a/1190000043418628#item-3

字符串存储的内存原理

  • String s = “abc”;直接赋值

    • 特点:

      • 此时字符串abc是存在字符串常量池中的。
      • 先检查字符串常量池中有没有字符串abc,如果有,不会创建新的,而是直接复用。如果没有abc,才会创建一个新的。

    所以,直接赋值的方式,代码简单,而且节约内存。

  • new出来的字符串

    • 看到new关键字,一定是在堆里面开辟了一个小空间。
    String s1 = new String(“abc”);
    
    String s2 = “abc”;

    s1记录的是new出来的,在堆里面的地址值。

    s2是直接赋值的,所以记录的是字符串常量池中的地址值。

  • ==号比较的到底是什么?

如果比较的是基本数据类型:比的是具体的数值是否相等。

如果比较的是引用数据类型:比的是地址值是否相等。

结论:==只能用于比较基本数据类型。不能比较引用数据类型。

本文参与了SegmentFault 思否面试闯关挑战赛,欢迎正在阅读的你也加入。
推荐问题
宣传栏