美文网首页
JVM 字符串常量池的垃圾回收

JVM 字符串常量池的垃圾回收

作者: 周小亿 | 来源:发表于2017-04-12 11:45 被阅读0次

    JVM字符串常量池会进行垃圾回收吗?
    会,但是对方法区的回收“成绩”比较难以令人满意,Java虚拟机规范中确实说过可以不要求虚拟机在方法区实现垃圾回收,而字符串常量池在方法区中。

    假设一个字符串"everor"已经进入了常量池,但是当前系统中没有一个String对象引用常量池中的"everor"常量(即String str = new String("everor");),也没有其他地方引用了这个字面量(即String str = "everor";),如果这个时候发生了内存回收,而且有必要的话,这个"everor"常量就会被系统清理出常量池。

    在HotSpot虚拟机中,方法区又被称为永久代,永久代这个概念在其它虚拟机(如BEA JRockit、IBM J9等)中是不存在的。但是使用永久代来实现方法区,并不是一个好主意,因为这样更容易遇到内存溢出问题。从JDK1.7开始,逐步使用元空间(MetaSpace)代替永久代的概念。元空间的内存大小取决于本地内存大小。元空间代替永久代,并不意味着字符串常量池就到了元空间,而是移到了堆中。

    延伸:何时将字符串对象引用放入字符串常量池?
    字符串常量池存放的是字符串对象的引用,字符串本身是一个对象,而对象是存放到堆中。当使用

    String str1 = "hello";
    String str2 = "hello";
    

    时,首先会看字符串常量池中是否已经有对“hello”字符串对象的引用,如果有,就返回池中的实例引用,如果不存在,就会实例化一个字符串到堆中,再在池中存一个对该字符串的引用。因此str1和str2指向的是同一个字符串对象。Java能够做这样的优化,是因为字符串是不可变的,可以不担心数据冲突进行共享。
    而当使用

    String str3 = new String("hello");
    

    时,不管字符串常量池中是否已经有hello字符串的引用,都会在堆中创建一个字符串,str3指向堆中的字符串,因此str3和str1 str2不是指向同一个对象。
    当使用

    String str4 = str3.intern();
    

    时,intern()方法表示如果str3的字符串在池中有,就返回池中的引用,否则在池中创建一个引用,再返回该引用,因此str4 str1 str2指向的是同一个字符串对象。

    参考
    -《深入理解Java虚拟机》

    相关文章

      网友评论

          本文标题:JVM 字符串常量池的垃圾回收

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