Mal*_*ker 4 java string hashmap string-interning
如果我有一个看起来像这样的HashMap:
HashMap<String, MyObject>
如果String键是一个字段MyObject,该字符串值是否存储两次?
所以当我添加条目时:
_myMap.put(myObj.getName(), myObj);
我是否在内存方面使用了两倍的字符串大小?或者Java在幕后做了哪些聪明的事情?
谢谢
pol*_*nts 16
除非您实际创建新的String值getName(),否则不会重复使用内存.
以下是一些澄清事物的例子:
String s1 = "Some really long string!";
String s2 = s1;
assert s1.equals(s2);
Run Code Online (Sandbox Code Playgroud)
在这里,s1 == s2; 它们指的是同一个String实例.你的内存使用量是2个参考变量(没什么大不了的),1个String实例和1个后备char[](占用内存的部分).
String s1 = "Some really long string!";
String s2 = new String(s1);
assert s1.equals(s2);
Run Code Online (Sandbox Code Playgroud)
在这里,s1 != s2; 他们指的是不同的String例子.但是,由于字符串是不可变的,因此构造函数知道它们可以共享相同的字符数组.你的内存使用量是2个参考变量,2个String实例(仍然没什么大不了的,因为......)和1个支持char[].
String s1 = "Some really long string!";
String s2 = new String(s1.toCharArray());
assert s1.equals(s2);
Run Code Online (Sandbox Code Playgroud)
就像以前一样s1 != s2.但是,这次使用了不同的构造函数char[].为了确保不变性,toCharArray() 必须返回其内部数组的防御副本(这样对返回数组的任何更改都不会改变String值).
[ toCharArray()返回] 一个新分配的字符数组,其长度为该字符串的长度,其内容初始化为包含此字符串表示的字符序列.
更糟糕的是,构造函数还必须将给定数组防御性地复制到其内部后备阵列,以确保不变性.这意味着多达3个字符数组的副本可能同时存在于内存中!其中1个将最终被垃圾收集,因此你的内存使用量是2个参考变量,2个String实例和2个支持char[]!现在你的内存使用量增加了一倍!
所以回到你的问题,只要你没有创建一个新的String值getName()(即如果你只是简单return this.name;),那么你就没事了.但是,如果您正在进行简单的连接(例如return this.firstName + this.lastName;),那么您的内存使用量将增加一倍!
以下代码说明了我的观点:
public class StringTest {
final String name;
StringTest(String name) {
this.name = name;
}
String getName() {
return this.name; // this one is fine!
// return this.name + ""; // this one causes OutOfMemoryError!
}
public static void main(String args[]) {
int N = 10000000;
String longString = new String(new char[N]);
StringTest test = new StringTest(longString);
String[] arr = new String[N];
for (int i = 0; i < N; i++) {
arr[i] = test.getName();
}
}
}
Run Code Online (Sandbox Code Playgroud)
您应首先验证上面的代码run(java -Xmx128m StringTest)而不抛出任何异常.然后,修改getName()到return this.name + "";并重新运行.这次你会得到一个OutOfMemoryError.
| 归档时间: |
|
| 查看次数: |
1340 次 |
| 最近记录: |