简体   繁体   English

堆:幸存者空间

[英]Heap: Survivor Space

I wrote a sample java application which allocates memory and then running forever.我编写了一个示例 java 应用程序,它分配内存然后永远运行。
why is the memory used by the survivor space 0kbytes ?!为什么幸存者空间使用的内存是0kbytes?!

    List<String> stringlist = new ArrayList<String>();

    while (true) {
        stringlist.add("test");
        if (stringlist.size() >= 5000000)
            break;
    }

    while (true)
        for (String s : stringlist);

Because "test" is a String literal it will end up in permanent memory not heap.因为“test”是一个字符串文字,它最终会出现在永久内存中而不是堆中。 Memory size of objects you create is 5000000 + 4*2 ~ 5MB which will easily fit into Eden space.您创建的对象的内存大小为 5000000 + 4*2 ~ 5MB,可以轻松放入 Eden 空间。

Modify调整

stringlist.add("test");

to

stringlist.add(new String("test"));

and you will get 5000000 * 4 * 2 =38MB which most probably will still fit into Eden.你会得到 5000000 * 4 * 2 =38MB,这很可能仍然适合 Eden。 You can either increase your list size or String length to make sure you have survivors.您可以增加列表大小或字符串长度以确保有幸存者。

"test" is a String literal and, regardless of how it's stored (this has changed during the Java development), the important point here is, that it is a single object . "test"是一个String字面量,不管它是如何存储的(这在 Java 开发过程中发生了变化),这里的重点是,它是一个单一的 object

Recall the Java Language Specification : 回忆一下 Java 语言规范

…a string literal always refers to the same instance of class String . …字符串字面量总是指类String同一个实例。 This is because string literals - or, more generally, strings that are the values of constant expressions (§15.28) - are "interned" so as to share unique instances, using the method String.intern这是因为字符串文字 - 或者更一般地说,作为常量表达式(第 15.28 节)的值的字符串 - 使用 String.intern 方法被“嵌入”以便共享唯一实例

So there are no new String s created within your loop as "test" always refers to the same String instance.所以在循环中没有创建新的String因为"test"总是指同一个String实例。 The only heap change occurs when the ArrayList 's internal capacity is exhausted.ArrayList的内部容量耗尽时,唯一的堆变化发生。


The memory finally required for the ArrayList 's internal array depends on the size of an object reference, usually it's 5000000*4 bytes for 32Bit JVMs and 64Bit JVMs with compressed oops and 5000000*8 bytes for 64Bit JVMs without compressed oops.最后所需的存储器ArrayList的内部阵列取决于一个对象引用的大小,通常是它的5000000*4 bytes与压缩糟糕和32位的JVM和64位的JVM 5000000*8 bytes为64位的JVM不启动压缩糟糕。

The interesting point here is described on www.kdgregory.com : www.kdgregory.com上描述了此处有趣的一点:

if your object is large enough, it will be created directly in the tenured generation.如果你的对象足够大,它会直接在年老代中创建。 User-defined objects won't (shouldn't!) have anywhere near the number of members needed to trigger this behavior, but arrays will: with JDK 1.5, arrays larger than a half megabyte go directly into the tenured generation.用户定义的对象不会(不应该!)接近触发此行为所需的成员数量,但数组将:在 JDK 1.5 中,大于半兆字节的数组直接进入年老代。

This harmonizes with these words found on oracle.com :这与oracle.com上的这些词一致:

If survivor spaces are too small, copying collection overflows directly into the tenured generation.如果幸存者空间太小,复制集合会直接溢出到年老代。

which gives another reason why larger arrays might not show up in the survivor space.这给出了为什么较大的数组可能不会出现在幸存者空间中的另一个原因。 So it depends on the exact configuration whether they do not appear because the were copied from Eden space to Tenured Generation or were created in the Tenured Generation in the first place.因此,它们是否不会出现取决于确切的配置,因为它们是从 Eden 空间复制到 Tenured Generation 或首先在 Tenured Generation 中创建的。 But the result of not showing up in the survivor space is the same.但是没有出现在幸存者空间的结果是一样的。


So when the ArrayList is created with its default capacity of 10 , the internal array is smaller than this threshold and so are the next ones to be created on each capacity enlargements.因此,当ArrayList以其默认容量10创建时,内部数组小于此阈值,因此每次容量扩大时将创建下一个数组。 However, at the time the new array exceeds this threshold, all old ones are garbage and hence won't show up as “survivors”.但是,当新数组超过此阈值时,所有旧数组都是垃圾,因此不会显示为“幸存者”。

So at the end of the first loop you have only one remaining array which has a size exceeding the threshold by far and hence bypassed the Survivor space.因此,在第一个循环结束时,您只剩下一个数组,该数组的大小远远超过阈值,因此绕过了 Survivor 空间。 Your second loop does not add anything to the memory management.您的第二个循环不会向内存管理添加任何内容。 It creates temporary Iterator s but these never “survive”.它创建临时Iterator但这些永远不会“存活”。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM