Home  >  Article  >  Java  >  How to use the intern method in Java String

How to use the intern method in Java String

WBOY
WBOYforward
2023-05-05 17:28:131059browse

    Introduction to constant pool

    There are 8 basic types and a special type String in the JAVA language. In order to make them run faster and save more memory, these types provide a concept of a constant pool (in the method area). The constant pool is similar to a cache provided by the JAVA system level. The eight basic types of constant pools are all coordinated by the system, and the String type constant pool is special.

    There are two main ways to use the String constant pool:

    String objects declared directly using double quotes will be directly stored in the constant pool.

    If the String object is not declared with double quotes, you can use the intern method provided by String to put it into the constant pool.

    Intern method introduction (JDK7)

    Prototype: public native String intern();

    Description:

    Query the current character from the string constant pool Whether the string exists (judged by equals).

    • If exists, returns the string reference in the constant pool.

    • If it does not exist, store the String object reference in the constant pool, and then return the String object reference.

    Return value: all return references to the string constant pool corresponding to the String variable.

    Example

    package com.example;
     
    public class Demo {
        public static void main(String argv[]) {
            String s = "test";
            System.out.println(s == s.intern());
        }
    }

    JDK6 and before: output false

    JDK7 and after: output true

    Principle (JDK6 and JDK7)

    The origin of the string in the constant pool

    Call String.intern() in JDK6 and before

    • If there is one in the constant pool, the constant will be returned The reference to this string in the pool

    • If there is no reference in the constant pool, copy a copy of the object and put it in the constant pool (permanent generation); the return value is the constant pool (permanent generation) A reference to the corresponding string instance in .

    JDK7 and later calls String.intern()

    • If there is one in the constant pool, return the reference to the string in the constant pool

    • If there is no constant pool, copy a reference and put it in the constant pool (heap); (JDK1.7 moved the String constant pool from the Perm area to the Java Heap area)

    Routine test

    Routine 1:

    package org.example.a;
     
    public class Demo {
        public static void main(String argv[]) {
            String s1 = new String("1");
            s1.intern();
            String s2 = "1";
            System.out.println(s1 == s2);
     
            String s3 = new String("1") + new String("1");
            s3.intern();
            String s4 = "11";
            System.out.println(s3 == s4);
        }
    }

    Result

    jdk6: false false
    jdk7: false true
    jdk8:false true

    Routine 2:

    package org.example.a;
     
    public class Demo {
        public static void main(String argv[]) {
            String s1 = new String("1");
            s1.intern();
            String s2 = "1";
            System.out.println(s1 == s2);
     
            String s3 = new String("1") + new String("1");
            String s4 = "11";
            s3.intern();
            System.out.println(s3 == s4);
        }
    }

    There is a swap in the second part of the above code.

    Result

    jdk6:false false
    jdk7:false false
    jdk8:false false

    Routine analysis

    In the picture below: the green line represents the content pointing of the String object. The red line represents the address pointing.

    jdk1.6

    Analysis of Routine 1 and Routine 2

    How to use the intern method in Java String

    As shown in the figure above. First let’s talk about the situation in jdk6. In jdk6, all the above prints are false, because the constant pool in jdk6 is placed in the Perm area, and the Perm area is completely separated from the normal JAVA Heap area. As mentioned above, if the string is declared using quotation marks, it will be generated directly in the string constant pool, and the new String object is placed in the JAVA Heap area. Therefore, comparing the object address of a JAVA Heap area with the object address of the string constant pool is definitely different, even if the String.intern method is called, it has no relationship.

    jdk1.7

    In Jdk6 and previous versions, the constant pool of strings is placed in the Perm area of ​​the heap. The Perm area is a static-like area that mainly stores some loads. The default size of class information, constant pool, method fragments, etc. is only 4m. Once a large amount of intern is used in the constant pool, a java.lang.OutOfMemoryError:PermGen space error will occur. In the jdk7 version, the string constant pool has been moved from the Perm area to the normal Java Heap area. The main reason why it needs to be moved is that the Perm area is too small. Of course, according to the news, jdk8 has directly canceled the Perm area and established a new meta area. It should be that jdk developers think that the Perm area is no longer suitable for the current development of JAVA. The string constant pool has been moved to the JAVA Heap area. Now explain why there are the above printed results.

    Analysis of Routine 1

    How to use the intern method in Java String

    ##1.String s1 = new String("1");

    Analysis: This line of code generates 2 objects ("1" in the constant pool and the string object in JavaHeap). s.intern(); This sentence means that the s1 object went to the constant pool to search and found that "1" was already in the constant pool.

    At this time, s1 points to the string object in Java Heap.

    2.String s2 = "1";

    Analysis: This line of code generates a reference to s2 pointing to the "1" object in the constant pool. The result is that the reference addresses of s1 and s2 are different.

    3.String s3 = new String("1") new String("1");

    分析:这行代码生成了2个对象(字符串常量池中的“1” 和 Java Heap中的 s3 引用指向的对象“11”(中间还有2个匿名的new String("1")我们不讨论它)。
    此时s3 是Java Heap中的字符串对象的引用,对象内容是”11″,此时常量池中是没有 “11”对象的。

    4.s3.intern();

    分析:这行代码将 s3中的"11"字符串放入String 常量池中,因为此时常量池中不存在"11"字符串,因此常规做法是跟 jdk6 图中表示的那样,在常量池中生成一个"11"的对象,关键点是 jdk7 中常量池不在Perm区域,而是在堆中了。常量池中不需再存储一份对象了,可以直接存储堆中的引用。这份引用指向s3引用的对象。 也就是说引用地址是相同的。

    此时,s3是Java Heap中的字符串对象的引用,对象内容是”11″,此时常量池中是有 “11”对象,它保存的就是s3引用地址。

    5.String s4 = "11"; 

    这行代码”11″是显式声明的,因此会直接去常量池中创建,创建时发现已经有这个对象了。

    此时:s4 == 常量池的“11”对象引用 == s3引用对象的引用

    例程2的分析

    How to use the intern method in Java String

    String s1 = new String("1");

    s1.intern();

    String s2 = "1";

    分析:s1.intern();,这一句往后放也不会有什么影响了,因为对象池中在执行第一句代码String s = new String("1");的时候已经生成“1”对象了。下边的s2声明都是直接从常量池中取地址引用的。 s1 和 s2 的引用地址是不会相等的。

    String s3 = new String("1") + new String("1");

    分析:这行代码生成了2个对象(字符串常量池中的“1” 和 Java Heap中的 s3 引用指向的对象“11”(中间还有2个匿名的new String("1")我们不讨论它)。

    此时s3 是Java Heap中的字符串对象的引用,对象内容是”11″,此时常量池中是没有 “11”对象的。

    String s4 = "11";

    分析:声明 s4 的时候常量池中是不存在“11”对象的,执行完后,s4是常量池里“11“对象的引用。

    s3.intern(); 

    分析:此时常量池中“11”对象已经存在了,不会有任何操作,s3仍然是堆中String对象的引用。因此 s3 != s4

    应用实例

    package org.example.a;
     
    import java.util.Random;
     
    public class Demo {
        static final  int MAX = 1000 * 10000;
        static final String[] arr = new String[MAX];
        public static void main(String argv[]) {
            Integer[] DB_DATA = new Integer[10];
            Random random = new Random(10 * 10000);
            for(int i = 0; i < DB_DATA.length; i++){
                DB_DATA[i] = random.nextInt();
            }
     
            long t = System.currentTimeMillis();
            for(int i = 0; i < MAX; i++){
                //arr[i] = new String(String.valueOf(DB_DATA[i % DB_DATA.length]));
                arr[i] = new String(String.valueOf(DB_DATA[i % DB_DATA.length])).intern();
            }
     
            System.out.println((System.currentTimeMillis() -t) + "ms");
            System.gc();
        }
    }

    上述代码是一个演示代码,其中有两条语句不一样,一条是使用 intern,一条是未使用 intern。

    运行的参数是:-Xmx2g -Xms2g -Xmn1500M

    不用intern

    2160ms

    How to use the intern method in Java String

    使用intern

    826ms

    How to use the intern method in Java String

    通过上述结果,我们发现不使用 intern 的代码生成了1000w 个字符串,占用了大约640m 空间。 使用了 intern 的代码生成了1345个字符串,占用总空间 133k 左右。其实通过观察程序中只是用到了10个字符串,所以准确计算后应该是正好相差100w 倍。虽然例子有些极端,但确实能准确反应出 intern 使用后产生的巨大空间节省。

    细心的同学会发现使用了 intern 方法后时间上有了一些增长。这是因为程序中每次都是用了 new String 后, 然后又进行 intern 操作的耗时时间,这一点如果在内存空间充足的情况下确实是无法避免的,但我们平时使用时,内存空间肯定不是无限大的,不使用 intern占用空间导致 jvm 垃圾回收的时间是要远远大于这点时间的。 毕竟这里使用了1000w次intern 才多出来1秒钟多的时间。

    The above is the detailed content of How to use the intern method in Java String. For more information, please follow other related articles on the PHP Chinese website!

    Statement:
    This article is reproduced at:yisu.com. If there is any infringement, please contact admin@php.cn delete