Java中String表示的大小不同

时间:2016-02-11 11:03:19

标签: java

我正在通过将String分解为其组成部分来比较在java中存储String的各种方法。我有这段代码:

final String message = "ABCDEFGHIJ";
System.out.println("As String " + RamUsageEstimator.humanSizeOf(message));
System.out.println("As byte[] " + RamUsageEstimator.humanSizeOf(message.getBytes()));
System.out.println("As char[] " + RamUsageEstimator.humanSizeOf(message.toCharArray()));

这是使用sizeof来衡量对象的大小。以上结果显示:

As String 64 bytes
As byte[] 32 bytes
As char[] 40 bytes

假设byte是8位且char是16位,为什么结果分别不是10个字节和20个字节?

String对象的开销是什么导致它成为基础byte[]大小的两倍?

这是使用

java version "1.8.0_60"
Java(TM) SE Runtime Environment (build 1.8.0_60-b27)
Java HotSpot(TM) 64-Bit Server VM (build 25.60-b23, mixed mode)

在OSX上

2 个答案:

答案 0 :(得分:6)

以下数据适用于Hotspot / Java 8 - 其他JVM / Java版本的数字会有所不同(例如,在Java 7中,String还有两个int字段。

new Object()占用12个字节的内存(由于内部事物,如对象标题)。

字符串有(括号中的字节数):

  • 对象标题(12),
  • char[]的引用(4 - 假设64位JVM中的压缩OOP),
  • int hash(4)。

这20个字节,但是对象被填充到8个字节的倍数=> 24.因此,在数组的实际内容之上已经有24个字节。

char[]有一个标题(12),一个长度(4),每个字符(10 x 2 = 20)填充到下一个8的倍数 - 或总共40个。

byte[]有一个标题(12),一个长度(4)和每个字节(10 x 1 = 10)= 26,填充到下一个8 = 32的倍数。

所以我们得到你的数字。

另请注意,字节数取决于您使用的编码 - 例如,如果您使用message.getBytes(StandardCharsets.UTF_16)重试,您将看到字节数组使用40个字节而不是32个字节。

您可以使用jol可视化内存使用情况并确认上述计算。 char[]的输出是:

 OFFSET  SIZE  TYPE DESCRIPTION                    VALUE
      0     4       (object header)                01 00 00 00 (00000001 00000000 00000000 00000000) (1)
      4     4       (object header)                00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4       (object header)                41 00 00 f8 (01000001 00000000 00000000 11111000) (-134217663)
     12     4       (object header)                0a 00 00 00 (00001010 00000000 00000000 00000000) (10)
     16    20  char [C.<elements>                  N/A
     36     4       (loss due to the next object alignment)
Instance size: 40 bytes (reported by Instrumentation API)

所以你可以看到12(前3行)的标题,长度(第4行),字符(第5行)和填充(第6行)。

类似于String(注意这排除了数组本身的大小):

 OFFSET  SIZE   TYPE DESCRIPTION                    VALUE
      0     4        (object header)                01 00 00 00 (00000001 00000000 00000000 00000000) (1)
      4     4        (object header)                00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                da 02 00 f8 (11011010 00000010 00000000 11111000) (-134216998)
     12     4 char[] String.value                   [A, B, C, D, E, F, G, H, I, J]
     16     4    int String.hash                    0
     20     4        (loss due to the next object alignment)
Instance size: 24 bytes (reported by Instrumentation API)

答案 1 :(得分:1)

您的每项测试都会估算Object的大小。在第一种情况下是String对象,在第二种情况下是byte数组对象,最后是char数组对象。作为类的实例,每个对象可能包含一些私有属性和其他类似的东西;所以你不能指望比以下更好的东西:一个String 10个字符,至少包含10个字符,每个字符长2个字节,那么整个大小应该是≥20个字节,这与你的结果一致。

对于字节/字符比较,你错了,因为字符串中的字节数组将为你提供给定编码的所有字节。可能会发生当前编码对char使用多个字节。

您可以查看JVM中ObjectString类和数组支持的Java源代码,以了解究竟发生了什么。