JVM中的字符串常量池

文章目录

  • JVM中的字符串常量池
    • 串池在不同版本JVM中的内存分布
    • intern()方法
      • 方法执行效果
      • 代码示例

JVM中的字符串常量池

串池在不同版本JVM中的内存分布

在jdk1.6中,字符串常量池和静态变量都位于方法区(HotSpot中称为永久代)中;在jdk7中,字符串常量池和静态变量转移到堆空间中;在jdk8中,新增元空间(MetaSpace,堆共享内存但不相连),去掉了方法区,方法区中的域信息、类信息、方法信息、JIT代码缓存、运行时常量池等移动至元空间。综上所诉,串池在jdk1.6中位于方法区,在jdk7和Jdk8中位于堆空间。

intern()方法

注意:判断串池中是否存在String,是利用equals方法。例如String name = new String("Pioneer") + new String("4");为了判断串池中是否存在name,底层相当于执行了if ("Pioneer4".equals(name))。另外,这里没有写String name = new String("Pioneer4");是因为编译器发现参数中出现“Pioneer4”后,后续就会将“Pioneer4”加入串池中。

方法执行效果

  1. jdk6
JVM中的字符串常量池_第1张图片
  • 如果串池中不存在该String,则将String复制到位于方法区的串池中,返回串池中的String常量的引用。
  • 如果出串池中存在该String,则直接返回串池中的String常量的引用。
  1. jdk7、8、9
JVM中的字符串常量池_第2张图片
  • 如果串池中不存在该String,则将指向该String对象的引用复制到串池中,并返回串池中保存的引用。
  • 如果串池中存在该String,则直接返回串池中的String常量的应用或者String对象的引用。

代码示例

  1. jdk6中,串池中不存在“xxx”和存在“xxx”的情况
public class StringPoolTest {
    public static void main(String[] args) {
        // 串池中不存在"jdk6"
        String jdkNew = new StringBuilder("jdk").append("6").toString();
        System.out.println(jdkNew == jdkNew.intern());
        System.out.println(System.identityHashCode(jdkNew));
        System.out.println(System.identityHashCode(jdkNew.intern()));

        // 串池中存在”Gosling“
        String name = "Gosling";
        String nameNew = new StringBuilder("Gos").append("ling").toString();
        System.out.println(System.identityHashCode(nameNew));
        System.out.println(System.identityHashCode(nameNew.intern()));
        System.out.println(nameNew == nameNew.intern());
    }
}

输出:
false
1507737389
235262323
536468534
1290300832
false
  1. jdk7中,串池中不存在”xxx“或String(“xxx”)引用,以及存在”xxx“或String(“xxx”)引用的情况
public class StringPoolTest {
    public static void main(String[] args) {
        // 串池中不存在"jdk7"
        System.out.println("---1---");
        String jdkNew = new StringBuilder("jdk").append("7").toString();
        System.out.println(jdkNew == jdkNew.intern());
        System.out.println(System.identityHashCode(jdkNew));
        System.out.println(System.identityHashCode(jdkNew.intern()));

        // 串池中存在"Gosling"
        System.out.println("---2---");
        String name = "Gosling";
        String nameNew = new StringBuilder("Gos").append("ling").toString();
        System.out.println(System.identityHashCode(nameNew));
        System.out.println(System.identityHashCode(nameNew.intern()));
        System.out.println(nameNew == nameNew.intern());
        System.out.println(name == nameNew.intern());

        // 串池中存在String("hobby")的引用
        System.out.println("---3---");
        String hobby = new StringBuilder("ping").append("pong").toString();
        hobby.intern();
        String hobbyNew = new String("pingpong");
        System.out.println(System.identityHashCode(hobbyNew));
        System.out.println(System.identityHashCode(hobbyNew.intern()));
        System.out.println(hobbyNew == hobbyNew.intern());
        System.out.println(hobby == hobbyNew.intern());
    }
}

输出:
---1---
true
1735600054
1735600054
---2---
21685669
2133927002
false
true
---3---
1836019240
325040804
false
true
  1. 期望在串池中创建数量大致相同的字符串,由于jdk1.6的串池在方法区中,所以会出现OOM;而在jdk7中,可以成功执行

运行参数:-XX:PermSize=10m -XX:MaxPermSize=15m

public class StringPoolSizeTest {
    public static void main(String args[]) {
        List list = new ArrayList();
        for (int i=0; i
  1. jdk7中使用intern()和不使用intern()的内存占用情况:
public class StringPoolGCTest {
    public static void main(String args[]) {
        Random random = new Random();
        List list = new ArrayList();
        for (int i=0; i<1000000; i++) {
        	// 测试执行intern()和不执行intern()的内存占用情况
            list.add(String.valueOf(random.nextInt(10)));
//            list.add(String.valueOf(random.nextInt(10)).intern());
        }

        try {
            Thread.sleep(1000*1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
  • 使用intern(),创建的多数String对象都会被GC回收,占用内存小
JVM中的字符串常量池_第3张图片 JVM中的字符串常量池_第4张图片
  • 不使用intern(),导致内存占用大,从JProfiler监控图中可以看到,存活的String实例的数量约等于创建的1000000:

    JVM中的字符串常量池_第5张图片
JVM中的字符串常量池_第6张图片

你可能感兴趣的:(java,jvm,java,jdk,内存泄漏,字符串)