String 的内存分配

一 点睛

在 Java 语言中有8种基本数据类型和一种比较特殊的类型 String。这些类型为了使它们在运行过程中速度更快、更节省内存,都提供了一种常量池的概念。
常量池就类似一个 Java 系统级别提供的缓存。8种基本数据类型的常量池都是系统协调的,String 类型的常量池比较特殊。它的主要使用方法有两种。
  • 直接使用双引号声明出来的 String 对象会直接存储在常量池中。 比如:String info="hello";
  • 如果不是用双引号声明的 String 对象,可以使用 String 提供的 intern() 方法。
Java6 及以前,字符串常量池存放在永久代。
Java7 中 Oracle的工程师对字符串池的逻辑做了很大的改变,即将字符串常量池的位置调整到 Java 堆内。
所有的字符串都保存在堆(Heap)中,和其他普通对象一样,这样可以让你在进行调优应用时仅需要调整堆大小就可以了。
字符串常量池概念原本使用得比较多,这个改动使得我们有足够的理由让我们重新考虑在 Java 7 中使用 String.intern()。
Java8 元空间,字符串常量在堆。

二 为什么 StringTable 从永久代调整到堆中

  • 永久代的默认比较小
  • 永久代垃圾回收频率低

三 实战——常量池存放在哪里

1 代码

/**
* jdk6中:
* -XX:PermSize=6m -XX:MaxPermSize=6m -Xms6m -Xmx6m
* <p>
* jdk8中:
* -Xms6m -Xmx6m
*/
public class StringTest3 {
    public static void main(String[] args) {
        // 使用 Set 保持着常量池引用,避免full gc回收常量池行为
        Set<String> set = new HashSet<String>();
        // 在 short 可以取值的范围内足以让 6MB 的PermSize 或 heap 产生 OOM 了。
        short i = 0;
        while (true) {
            set.add(String.valueOf(i++).intern());
        }
    }
}

2 JDK6 测试(-XX:PermSize=6m -XX:MaxPermSize=6m -Xms6m -Xmx6m)——OOM发生在永久代

Exception in thread "main" java.lang.OutOfMemoryError: PermGen space

    at java.lang.String.intern(Native Method)

    at com.atguigu.java.StringTest3.main(StringTest3.java:20)

3 JDK8 测试(-Xms6m -Xmx6m)——OOM发生在堆空间

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

    at java.util.HashMap.resize(HashMap.java:704)

    at java.util.HashMap.putVal(HashMap.java:663)

    at java.util.HashMap.put(HashMap.java:612)

    at java.util.HashSet.add(HashSet.java:220)

    at com.atguigu.java.StringTest3.main(StringTest3.java:20)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值