我正在通过将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上
答案 0 :(得分:6)
以下数据适用于Hotspot / Java 8 - 其他JVM / Java版本的数字会有所不同(例如,在Java 7中,String
还有两个int
字段。
new Object()
占用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中Object
,String
类和数组支持的Java源代码,以了解究竟发生了什么。