【发布时间】:2012-08-14 01:46:48
【问题描述】:
我听到一位同事说,如果我在 Java 类中删除了一个 String 成员,即使 String 为空,我也会支付“24 个字节”。那准确吗? Integer、Float、Double 一样吗? (与 int、float、double 不同,它们分别只有 4、4 和 8 个字节)。
【问题讨论】:
标签: java string size primitive-types
我听到一位同事说,如果我在 Java 类中删除了一个 String 成员,即使 String 为空,我也会支付“24 个字节”。那准确吗? Integer、Float、Double 一样吗? (与 int、float、double 不同,它们分别只有 4、4 和 8 个字节)。
【问题讨论】:
标签: java string size primitive-types
您将为 reference 支付 4 或 8 个字节。是否为每个“容器”对象实例支付额外的 object 取决于您如何获取空字符串。例如,如果您使用文字 "",那么 所有 实例将引用同一个对象,因此您只需为引用本身付费。
如果您为每个实例创建一个单独的空字符串,那么显然会占用更多内存。
【讨论】:
Object 的普通空实例支付的字节数。您为Integer支付相同的金额。
确实,您会为整数支付比 int 更多的费用。我记得检查了几个 Java 版本,而 Integer 又占用了大约 24 个字节。 只要您的字符串指向一个空对象(也就是什么都没有),您只需要在内存中保留一个指针,而且我认为 JVM 不会保留一个位置来初始化它,在这种情况下您不会浪费了 24 个字节,只有 8 个。如果您创建字符串(甚至是空字符串“”),那么您已经在内存中拥有一个对象,并且由于所有对象都继承 Object,它们带有一些包袱并占用比您直观预期更多的内存. 根据您对字符串的使用,一个常见的解决方案是从一个空对象开始,并在需要时延迟初始化它。
【讨论】:
LinkedList 是一个已知的内存消耗者。 ArrayList 在这方面要好得多。
借用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();
}
【讨论】:
字符串由对象头(HotSpot 上 2 个字,J9 上 3 个字)、int 字段和 char 数组引用组成。 Char 数组本身由 header、int 字段和数组的其余部分组成。一切都填充到 8 个字节。通常,字符编码为每个字符 2 个字节。一些 JVM 可以为 char 使用替代编码。在某一时刻,J9 可以用 UTF8 编码字符串。如果字符串由简单字符组成(本质上是 UTF-8 的 1 字节编码字形,如英文字母、数字等),现代 HotSpot 将使用每个字符 1 个字节。否则,它对整个数组使用每个字符 2 个字节。
如此深的空字符串大小是这样的:
通常,不会分配空字符数组,因为它的值将被推断出来。毕竟所有空字符数组都是相等的。因此,空字符串的实际惩罚将是浅字符串大小;对于当今最常见的情况(具有压缩引用的 64 位 HotSpot),这是 24 字节。
IBM J9 JVM 有更大的对象头,它会分配一些 more.
【讨论】: