java - 在 Java 中,物理内存如何保存每个长度为 1MB 的字符串 HashMap ?

标签 java string memory-management

这个问题困扰了我一段时间,我似乎无法从 oracle java 资源中找到任何答案。有没有人对此事有任何线索:

我理解一个字符串其实就是一个char数组。但是,我想知道在以下两种情况下,数据在物理内存中的存储方式有何不同:

案例 1) 总共 10 个字符串放入 HashMap 中。每个字符串都以 0 长度开始。每一秒,每个字符串都追加 1000 字节。直到每个达到1MB

案例 2)总共 10 个字符串放入 HashMap 中。每个字符串以 1M 长度(带空格)开头。每一秒,每个字符串都被 替换 为 1000 字节。直到它替换了所有的 1MB。

对于case1,会不会因为字符串长度不断增长,需要进行新的分配,导致在物理内存中进行更多的引用?还是将数据“推”到后面以便分配下一个可用内存?

对于案例 2,这是否意味着更少的引用需求(或者实际上不需要引用),因为字符串首先以 1MB 长度启动?

最后,我想知道这两种情况对垃圾收集器或内存分配性能有什么影响吗?

最佳答案

实际上,在处理字符串时,它们几乎是一样的。

简单地说,字符串是不可变的。因此,如果您有一个包含 1000 个字符的字符串,并向其追加 1000 个字符,那么您将拥有一个包含 2000 个字符的字符串,而前一个字符串可用于垃圾回收。

如果你有一个 1M 的 String 并改变它,你就有了一个新的 1M 的 String,旧的可以用于垃圾回收。由于字符串是不可变的,因此没有拆分旧字符串、删除所需内容、添加新字符串以及将旧字符串和新字符串附加在一起的花招。相反,它只是简单地将其复制到新版本中。

还有其他结构表现更好,但仍然存在类似问题。

例如,如果您有一个 StringBuilder,在 1000 + 1000 的情况下,它的行为几乎与普通字符串完全一样。但是,如果您知道会发生这种情况,您可以将它预先分配到,比如 10,000,然后它会简单地复制到预先分配的空间,而不是扔掉整个旧工具包。

字符串不变性的另一个特点是字符串可以共享。

一个简单的例子是这样的:

String a = "abc123";
String b = a.substring(1, 3);

这将有一个包含 6 个字符的数组(“abc123”),但是两个字符串都将指向该数组,'b' 字符串将指向数组中与原始数组的偏移量。

缺点是:

String a = ".../pinky 1 MILLION characters...";
String b = a.substr(1, 3);
a = null;

“b”现在指向“a”使用的原始缓冲区,即使它只“看到”3 个字符。因此,您的 'b' 字符串实际上占用了 1M 个字符的内存。

关于java - 在 Java 中,物理内存如何保存每个长度为 1MB 的字符串 HashMap ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6906908/

相关文章:

c - 获取处理器的内存粒度

java - 任何人都可以指出一个好的 java 函数/对象/方法的方向吗?

java - 哪种 Paypal 方法更适合用于向用户付款 - 批量付款或自适应付款?

java - 比较不同文件(CSV,Excel)Java Apache commons 和 poi 中两列的日期以了解日期相似的地方

python - 在 Pandas 系列中拆分字符串和整数 - Python

python - 如何删除python中的标点符号?

java - 使用数组排序

python - python 字符串中出现频率最高的一个或多个字母

c++ - 可遍历内存池的数据结构

c++ - 通过池分配器中的内存地址访问空闲列表节点