【问题标题】:Java - inline initialized string array memory allocation on heap?Java - 堆上的内联初始化字符串数组内存分配?
【发布时间】:2012-10-01 02:31:54
【问题描述】:

String[] stringArray = new String[] { "abc", "xyz" };

执行这一行,在PERMGEN 空间中创建了两个字符串文字“abc”和“xyz”。由于初始化有一个新的运算符,我不确定 HEAP 上是否分配了任何内存。

谢谢大家。

【问题讨论】:

  • @Eun 但在这种情况下,它仅适用于数组对象(String[])。字符串位于 permgen 空间中(在 Java 6 中)。
  • 堆包含一个数组。字符串包含在其他地方。

标签: java string heap-memory permgen


【解决方案1】:

除了字符串字面量之外的所有对象都是在堆上创建的。从 Java 7 开始,字符串文字也在堆上创建。

理论上,逃逸分析可以防止在堆上创建new 对象,并可能改用堆栈。这在 AFAIK 实践中很少发生。


在回答 EJP 问题时,我没有资助一个重要的例子,但是

来自http://www.oracle.com/technetwork/server-storage/ts-7392-159315.pdf第22页

New Technology: Escape Analysis
Definition: An object escapes the thread that allocated it if
some other thread can ever see it
If an object doesn't escape, we can abuse it
• Object explosion: allocate object's fields in different places
• Scalar replacement: store scalar fields in registers
• Thread stack allocation: store fields in stack frame
• Eliminate synchronization
• Eliminate initial object zero'ing
• Eliminate GC read / write barriers
Enabled with -XX:+DoEscapeAnalysis in JDKTM version 6

理论上这个特性已经存在了一段时间,但它并不经常工作(即使找到一个人为的例子也很困难)在 Java 7 中,找到人为的例子更容易。 ;)

public class UsesWrappersMain {
    public static void main(String... args) {
        for (int j = 0; j < 10; j++) {
            long used = used(), count = 0;
            for (int i = 0; i < 2000; i++) {
                count += printSum();
            }
            // add an object to show it is working
            byte[] b = new byte[16];
            long used2 = used();
            System.out.printf("Memory used for %,d iterations was %,d bytes%n", count, used2 - used);
        }
    }

    private static int printSum() {
        int count = 0;
        for (float i = 0; i < 10000; i++) {
            // definitively not autoboxed.
            Float j = new Float(i);
            count++;
        }
        return count;
    }

    private static long used() {
        return Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
    }
}

使用 -XX:-UseTLAB 运行时打印

Memory used for 20,000,000 iterations was 480,888 bytes
Memory used for 20,000,000 iterations was 32 bytes
Memory used for 20,000,000 iterations was 32 bytes
Memory used for 20,000,000 iterations was 32 bytes
Memory used for 20,000,000 iterations was 32 bytes
Memory used for 20,000,000 iterations was 32 bytes
Memory used for 20,000,000 iterations was 32 bytes
Memory used for 20,000,000 iterations was 0 bytes
Memory used for 20,000,000 iterations was 0 bytes
Memory used for 20,000,000 iterations was 0 bytes

如果你添加-XX:-DoEscapeAnalysis 不是默认的

Memory used for 20,000,000 iterations was 320,000,928 bytes
Memory used for 20,000,000 iterations was 320,000,032 bytes
Memory used for 20,000,000 iterations was 320,000,032 bytes
Memory used for 20,000,000 iterations was 320,000,032 bytes
Memory used for 20,000,000 iterations was 320,000,032 bytes
Memory used for 20,000,000 iterations was 320,000,032 bytes
Memory used for 20,000,000 iterations was 320,000,032 bytes
Memory used for 20,000,000 iterations was 320,000,144 bytes
Memory used for 20,000,000 iterations was 320,000,032 bytes
Memory used for 20,000,000 iterations was 320,000,032 bytes

【讨论】:

  • 任何字段引用也是如此。
  • 谢谢彼得。所以“字符串文字也是在堆上创建的。”表示字符串池有两个副本(heap 和 permgen),或者它只是在 Heap 上创建的
  • 在堆中只是为了防止 PermGen 因String.intern() 或大量字符串文字而被填满。
  • String s1 = "Java"; String s2 = new String("Java"); `System.out.println(s1 == s2);'这返回false,但是您说文字是在堆中分配的内存,但是我认为您的意思是在堆中分配了字符串池,但是使用new在堆上分配的字符串与在池中创建的字符串文字不同(驻留在堆上)。我说的对吗
  • 当你使用 new String("Java"); 时,它保证了新对象的创建。因此,无论它们存储在哪里,您的 s1==s2 都会返回 false。运行它并希望它能消除一些疑问, String s1= new String("Java");字符串 s2= 新字符串(“Java”); System.out.println(s1==s2);
【解决方案2】:

当你执行这个时会发生什么,你会得到:

  • permgen 中的两个字符串文字
  • 堆中的两个字符串对象
  • 堆中的一个字符串数组对象

即使实际的文字字符串保存在 permgen 的字符串池中,String-对象 仍然存储在堆中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-03-24
    • 2011-05-12
    • 2011-06-02
    • 1970-01-01
    • 1970-01-01
    • 2011-11-07
    • 1970-01-01
    相关资源
    最近更新 更多