我使用java从文件中读取数据,将数据复制到较小的数组并将这些数组放在Hashtables中。我注意到Hashmap比原始文件消耗更多内存(大约两倍)!知道为什么吗?
这是我的代码:
public static void main(final String[] args) throws IOException {
final PrintWriter writer = new PrintWriter(new FileWriter("test.txt",
true));
for(int i = 0; i < 1000000; i++)
writer.println("This is just a dummy text!");
writer.close();
final BufferedReader reader = new BufferedReader(new FileReader(
"test.txt"));
final HashMap<Integer, String> testMap = new HashMap<Integer, String>();
String line = reader.readLine();
int k = 0;
while(line != null) {
testMap.put(k, line);
k++;
line = reader.readLine();
}
}
答案 0 :(得分:6)
这不是HashMap
的问题,它通常是Java对象的问题。每个对象都有一定的内存开销,包括数组和HashMap
中的条目。
但更重要的是:字符数据占用内存空间的两倍。原因是Java uses 16 bits for each character,而文件可能用ASCII或UTF-8编码,每个字符只使用7或8位。
更新:您无能为力。您发布的代码原则上很好。它只适用于大文件。如果仔细调整HashMap
,或者可以使用字节数组而不是字符串来存储字符(假设所有内容都是ASCII或单字节UTF-8),则可能会做得更好一些。 / p>
但最后,为了解决你的内存不足问题,正确的方法是重新考虑你的程序,这样你就不必立即将整个文件读入内存。
无论您使用该文件的内容是什么,请考虑在从磁盘读取文件时是否可以执行此操作(这称为流式传输)或者可能提取相关部分并仅存储这些部分。您还可以尝试随机访问该文件。
我建议你仔细阅读这些内容,尝试一下并回来问一个针对你的应用程序的新问题。因为这个帖子太长了。
答案 1 :(得分:6)
地图是一种“可扩展”结构 - 当它达到其容量时,它会被调整大小。因此,有可能说地图使用的40%的空间实际上是空的。如果您知道地图中有多少条目,则可以使用特殊构造函数以最佳方式调整地图大小:
Map<xx,yy> map = new HashMap<> (length, 1);
即使您这样做,地图仍将使用比所包含项目的实际大小更多的空间。
更详细地说:HashMap的大小在达到(capacity * loadFactor)时会增加一倍。 HashMap的默认加载因子是0.75。
示例:
修改强>
这个简单的代码让您了解实践中会发生什么 - 输出是:
threshold of empty map = 8192
size of empty map = 35792
threshold of filled map = 8192
size of filled map = 1181712
threshold with one more entry = 16384
size with one more entry = 66640
表示如果您添加的最后一个项目强制地图调整大小,则可以人为地增加地图的大小。不可否认,这并不能说明您所观察到的整体效果。
public static void main(String[] args) throws java.lang.Exception {
Field f = HashMap.class.getDeclaredField("threshold");
f.setAccessible(true);
long mem = Runtime.getRuntime().freeMemory();
Map<String, String> map = new HashMap<>(2 << 12, 1); // 8,192
System.out.println("threshold of empty map = " + f.get(map));
System.out.println("size of empty map = " + (mem - Runtime.getRuntime().freeMemory()));
mem = Runtime.getRuntime().freeMemory();
for (int i = 0; i < 8192; i++) {
map.put(String.valueOf(i), String.valueOf(i));
}
System.out.println("threshold of filled map = " + f.get(map));
System.out.println("size of filled map = " + (mem - Runtime.getRuntime().freeMemory()));
mem = Runtime.getRuntime().freeMemory();
map.put("a", "a");
System.out.println("threshold with one more entry = " + f.get(map));
System.out.println("size with one more entry = " + (mem - Runtime.getRuntime().freeMemory()));
}
答案 2 :(得分:0)
需要存储HashMap(和数组)的实现内部有很多东西。数组长度就是这样一个例子。不确定这是否会占到 double ,但它肯定会占一些。