【问题标题】:Size of empty Java String空 Java 字符串的大小
【发布时间】:2012-08-14 01:46:48
【问题描述】:

我听到一位同事说,如果我在 Java 类中删除了一个 String 成员,即使 String 为空,我也会支付“24 个字节”。那准确吗? Integer、Float、Double 一样吗? (与 int、float、double 不同,它们分别只有 4、4 和 8 个字节)。

【问题讨论】:

    标签: java string size primitive-types


    【解决方案1】:

    您将为 reference 支付 4 或 8 个字节。是否为每个“容器”对象实例支付额外的 object 取决于您如何获取空字符串。例如,如果您使用文字 "",那么 所有 实例将引用同一个对象,因此您只需为引用本身付费。

    如果您为每个实例创建一个单独的空字符串,那么显然会占用更多内存。

    【讨论】:

    • @Frank:如果他真的这么建议,我会怀疑他说的其他任何话......
    • 弗兰克,我怀疑他是在暗示你所说的,因为 24 确实是你在典型的 64 位 HotSpot 上为Object 的普通空实例支付的字节数。您为Integer支付相同的金额。
    • @KumarVivekMitra:你已经得到了很好的答案。
    • @KumarVivekMitra 这种拉客行为实在是不妥。
    • 弗兰克,这就是他不对正确的地方,但我仍然怀疑他的意思是参考尺寸。他只是将声明与它可能引用的实际对象混淆了——并忘记了字符串是不可变的,因此可以广泛共享,尤其是通过常量池。
    【解决方案2】:

    确实,您会为整数支付比 int 更多的费用。我记得检查了几个 Java 版本,而 Integer 又占用了大约 24 个字节。 只要您的字符串指向一个空对象(也就是什么都没有),您只需要在内存中保留一个指针,而且我认为 JVM 不会保留一个位置来初始化它,在这种情况下您不会浪费了 24 个字节,只有 8 个。如果您创建字符串(甚至是空字符串“”),那么您已经在内存中拥有一个对象,并且由于所有对象都继承 Object,它们带有一些包袱并占用比您直观预期更多的内存. 根据您对字符串的使用,一个常见的解决方案是从一个空对象开始,并在需要时延迟初始化它。

    【讨论】:

    • 70 字节已经很远了。您为引用付费(通常只有 4 个字节——到目前为止,甚至 Steven 也是如此)和堆上的对象的 24 个字节。
    • 这更有意义,我主要记得 Integer 占用了这么多,所以我用 int 重新实现了 LinkedList。
    • 是的,LinkedList 是一个已知的内存消耗者。 ArrayList 在这方面要好得多。
    【解决方案3】:

    借用this answer:程序为空字符串打印 32 个字节(字符串池中的 "" 为 0)。

    public static void main(String... args) {
        long free1 = free();
        String s = "";
        long free2 = free();
        String s2 = new String("");
        long free3 = free();
        if (free3 == free1) System.err.println("You need to use -XX:-UseTLAB");
        System.out.println("\"\" took " + (free1 - free2) + " bytes and new String(\"\") took " + (free2
                - free3) + " bytes.");
    }
    
    private static long free() {
        return Runtime.getRuntime().freeMemory();
    }
    

    【讨论】:

    • new String("") 的空字符数组是共享的。 new String("X") 结果为 72 个字节。
    • @R.Moeller 这是一个很好的观点 - 但我很确定空字符串将始终在字符串池中,即使您不使用它显式(它可能在 JDK 内部代码的许多实例中使用)...所以这取决于您要测量的内容。
    • 我认为它是共享的零长度字符数组..所以 new String("") 创建一个新字符串但不创建一个字符数组。所以 24 字节是空字符串的长度,但 1 长度字符串的长度是 > 72 字节
    【解决方案4】:

    字符串由对象头(HotSpot 上 2 个字,J9 上 3 个字)、int 字段和 char 数组引用组成。 Char 数组本身由 header、int 字段和数组的其余部分组成。一切都填充到 8 个字节。通常,字符编码为每个字符 2 个字节。一些 JVM 可以为 char 使用替代编码。在某一时刻,J9 可以用 UTF8 编码字符串。如果字符串由简单字符组成(本质上是 UTF-8 的 1 字节编码字形,如英文字母、数字等),现代 HotSpot 将使用每个字符 1 个字节。否则,它对整个数组使用每个字符 2 个字节。

    如此深的空字符串大小是这样的:

    • 32 位 HotSpot 上的 32 个字节(String 为 16 个字节,char[] 为 16 个字节)
    • 64 位 HotSpot 上 56 字节(String 为 32 字节,char[] 为 24 字节)
    • 64 位 HotSpot 上的 40 字节,带有压缩引用(24 字节用于字符串,16 字节用于 char[])

    通常,不会分配空字符数组,因为它的值将被推断出来。毕竟所有空字符数组都是相等的。因此,空字符串的实际惩罚将是浅字符串大小;对于当今最常见的情况(具有压缩引用的 64 位 HotSpot),这是 24 字节

    IBM J9 JVM 有更大的对象头,它会分配一些 more.

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多