java - 字符串创建和字符数组内存分配

标签 java string memory permgen

我已经阅读了很多关于创建 String 时内存分配的相互矛盾的文章。 有些文章说 new 运算符在堆中创建一个字符串,而字符串字面量在字符串池 [堆] 中创建,而有些文章则说 new 运算符在堆中创建一个对象,在字符串池中创建另一个对象。

为了对此进行分析,我编写了以下程序,打印了 String char 数组和 String 对象的哈希码:

import java.lang.reflect.Field;

public class StringAnalysis {

    private int showInternalCharArrayHashCode(String s)
            throws SecurityException, NoSuchFieldException,
            IllegalArgumentException, IllegalAccessException {
        final Field value = String.class.getDeclaredField("value");
        value.setAccessible(true);
        return value.get(s).hashCode();
    }

    public void printStringAnalysis(String s) throws SecurityException,
            IllegalArgumentException, NoSuchFieldException,
            IllegalAccessException {
        System.out.println(showInternalCharArrayHashCode(s));

        System.out.println(System.identityHashCode(s));

    }

    public static void main(String args[]) throws SecurityException,
            IllegalArgumentException, NoSuchFieldException,
            IllegalAccessException, InterruptedException {
        StringAnalysis sa = new StringAnalysis();
        String s1 = new String("myTestString");
        String s2 = new String("myTestString");
        String s3 = s1.intern();
        String s4 = "myTestString";

        System.out.println("Analyse s1");
        sa.printStringAnalysis(s1);

        System.out.println("Analyse s2");
        sa.printStringAnalysis(s2);

        System.out.println("Analyse s3");
        sa.printStringAnalysis(s3);

        System.out.println("Analyse s4");
        sa.printStringAnalysis(s4);

    }

}

此程序打印以下输出:

Analyse s1
1569228633
778966024
Analyse s2
1569228633
1021653256
Analyse s3
1569228633
1794515827
Analyse s4
1569228633
1794515827

从这个输出中可以清楚地看出,无论字符串是如何创建的,如果字符串具有相同的值,则它们共享相同的字符数组。

现在我的问题是这个 chararray 存储在哪里,是存储在堆中还是存储在 permgen 中?我还想了解如何区分堆内存地址和 permgen 内存地址。

如果它存储在 permgen 中,我有一个大问题,因为它会占用我宝贵的有限 permgen 空间。如果 char 数组没有存储在 permgen 中而是存储在堆中,那么这是否意味着字符串文字也使用堆空间 [这是我从未读过的东西]。

最佳答案

来自字符串源

 public String(String original) {
        this.value = original.value;
        this.hash = original.hash;
    }

很明显,使用此构造函数创建的字符串与原始字符串共享 char 数组(值)。

重要的是要注意 API 不保证这种共享:

初始化新创建的 String 对象,使其表示与参数相同的字符序列;换句话说,新创建的字符串是参数字符串的副本。除非需要原始的显式副本,否则不需要使用此构造函数,因为字符串是不可变的

例如,String.substring 用于与原始字符串共享 char 数组,但在最新版本的 Java 1.7 中,String.substring 复制了 char 数组。

关于java - 字符串创建和字符数组内存分配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16152311/

相关文章:

java - 反射不返回正确的实例

java - 使用 iText Java 循环创建新的 pdf

python - 将列表的字符串表示形式转换为列表

c++ - 如何实现内存堆

php - 内存耗尽cakephp数据库查询

java - FXMLLoader 未从 JUnitTest 加载(相对路径问题)

javascript - 在 Javascript 中将非 unicode 二进制字符串转换为字节数组

c++ - 将字符串中的字符转换为大写不起作用

android - 如何将图片放入应用程序的内存中?

java - 在 hibernate 中将枚举映射到字符串