IE盒子

搜索
查看: 135|回复: 0

java字符串常量池保存在哪里?如何证明?

[复制链接]

2

主题

5

帖子

8

积分

新手上路

Rank: 1

积分
8
发表于 2023-1-18 09:06:01 | 显示全部楼层 |阅读模式
java字符串常量池保存在哪里?如何证明?
    有一次被问到java字符串常量池保存在哪里?如何证明?其实这个问题我想不会难倒大多数人,但是问题如何证明呢?我当时也一脸懵逼,因为确实不知道怎么证明,了解到的也只是从一些博客或贴子中得来,也不知是否正确。以下是经过一番学习整理后的一些个人结论。
    首先看看Oracle官方的说明,以下是JDK7 Java虚拟机(HotSpot)相关的一些较大更改,其中就有字符串常量池的说明。链接地址:Java Virtual Machine Enhancements in JDK 7


    大概意思是说在JDK7中,内部字符串不再分配在Java堆的永久代中,而是与应用程序创建的其他对象一起分配在Java堆的主要部分(称为年轻代和老年代)中。
    可见字符串常量池在JDK7之前是保存在永久代中的,在JDK7及之后,是保存在堆空间中。
    以上是从官方的文档中找到的证明。
    以下是通过代码的角度来证明字符串常量池的保存位置。
大概证明思路是,固定堆空间、永久代或元空间的大小,然后不断的往字符串常量池中添加字符,直到空间被占用完,看报出的错误是什么。

  • 创建一个简单的MyTest.java。在main方法里利用String类的intern()方法将字符串添加到常量池。
public class MyTest {

/**
* JDK1.6/1.7 运行参数设置
* -Xms9m -Xmx9m -XX:PermSize=9m -XX:MaxPermSize=9m -XX:-UseGCOverheadLimit
*
* JDK1.8 运行参数设置
* -Xms9m -Xmx9m -XX:MetaspaceSize=9m -XX:MaxMetaspaceSize=9m -XX:-UseGCOverheadLimit
*
* -XX:-UseGCOverheadLimit 添加这个为了排除其他干扰,避免垃圾回收内存比例达不到预期值而报 java.lang.OutOfMemoryError: GC Overhead limit exceeded
*/

    public static void main(String[] args) {
        System.out.println("Hello");
        //使用list保持常量池引用,避免GC回收
        List list = new ArrayList();
        int i = 0;
        while (true){
            list.add(String.valueOf(i).intern());
            i ++;
        }
    }
}2. 配置运行JVM参数,使用JDK6、JDK7、JDK8版本查看运行结果。JVM参数中固定了堆空间、永久代或元空间的大小。
        参数说明:
        -Xms:初始化堆空间大小
        -Xmx: 最大堆空间大小
        -XX:PermSize: 代初始永久代大小
        -XX:MaxPermSize:最大永久化大小
        -XX:MetaspaceSize:初始化元空间大小
        -XX:MaxMetaspaceSize:最大元空间大小                    

  • JDK6运行,报了 java.lang.OutOfMemoryError: PermGen space 的错误,可见JDK6字符串常量池是保存在永久代中。





  • JDK7、JDK8运行,都报了 java.lang.OutOfMemoryError: Java heap space 的错误,可见JDK7、JDK8字符串常量池是保存在堆空间中。




    以上从代码角度证明了,java字符串常量池在JDK7之前是保存在永久代中的,在JDK7及之后,是保存在堆空间中。
    好了,本次的分享到此结束,以后要是再有人让你证明Java字符串常量池保存在哪里,不至于一脸懵逼了,至少可以把我的文章甩给他看。   
关注我微信“务实程序猿”,不定时更新分享更多的知识!转载请标明出处。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表