14

如果我在磁盘上获取大约2kB的 XML 文件并将内容作为 String 加载到 Java 中的内存中,然后测量对象大小,它大约为 33kB

为什么规模大幅增加?
如果我在 C++ 中做同样的事情,内存中的结果字符串对象更接近 2kB。

为了测量 Java 中的内存,我使用Instrumentation。对于 C++,我采用序列化对象(例如字符串)的长度。

4

6 回答 6

4

假设您的 XML 文件主要包含 ASCII 字符并使用将它们表示为单个字节的编码,那么您可以预计内存大小至少是两倍,因为 Java 在内部使用 UTF-16(我听说过一些 JVM尝试优化这一点,虽然)。除此之外,还有 2 个对象(String 实例和一个内部 char 数组)的开销,其中包含一些字段,IIRC 总共大约 40 个字节。

因此,除非您使用的是奇怪的 JVM,否则您 33kb 的“对象大小”绝对不正确。你用来测量它的方法一定有问题。

于 2013-05-24T07:14:24.880 回答
4

我认为这涉及到多种因素。首先,正如 Bruce Martin 所说,java 中的对象每个对象有 16 个字节的开销,而 c++ 没有。其次,Java 中的字符串可能是每个字符 2 个字节而不是 1 个。第三,Java 为其字符串保留的内存可能比 C++ 的 std::string 多。

请注意,这些只是可能产生巨大差异的想法。

于 2013-05-24T07:14:08.070 回答
2

在 Java String 对象中有一些额外的数据,这会增加它的大小。
它是对象数据、数组数据和其他一些变量。这可以是数组引用、偏移量、长度等。

有关详细信息,请访问http://www.javamex.com/tutorials/memory/string_memory_usage.shtml

于 2013-05-24T07:11:02.063 回答
1

String:String 的内存增长跟踪其内部 char 数组的增长。但是,String 类又增加了 24 个字节的开销。对于大小为 10 个字符或更小的非空字符串,相对于有用负载(每个字符 2 个字节加上长度 4 个字节)的额外开销成本的范围为 100% 到 400%。

更多: Java中对象的内存消耗是多少?

于 2013-05-24T07:46:41.883 回答
0

是的,你应该 GC 并给它时间来完成。只是 System.gc(); 并在循环中打印 totalMem()。您还最好在数组中创建一百万个字符串副本(测量空数组的大小,然后用字符串填充),以确保您测量的是字符串的大小,而不是您的程序中可能存在的其他服务对象的大小。单独的字符串不能占用 32 kb。但是 XML 对象的层次结构可以。

话虽如此,我无法抗拒在 Java 世界中没有人关心内存(和缓存命中)的讽刺意味。我们知道 JIT 正在改进,在某些情况下它可以胜过原生 C++ 代码。因此,无需担心内存优化。初步优化是万恶之源。

于 2013-05-24T07:19:40.777 回答
0

如其他答案所述,Java 的 String 增加了开销。如果您需要在内存中存储大量字符串,我建议您将它们存储为 byte[] 代替。这样做内存中的大小应该与磁盘上的大小相同。

字符串 -> 字节 [] :

String a = "hello";
byte[] aBytes = a.getBytes();

字节[] -> 字符串:

String b = new String(aBytes);
于 2016-02-04T13:19:24.377 回答