fia*_*lli 14 java memory heap serializable cloneable
我正在使用一个内部类,它是HashMap的子类.我有一个String关键和double[]价值观.我每次存储约200个双打double[].我应该使用大约700 MB来存储密钥,指针和双打.然而,内存分析显示我需要更多(略多于2 GB).
使用TIJmp(分析工具)我看到有一个char[]使用了几乎一半的总内存.TIJmp表示char[]来自Serializable和Cloneable.其中的值范围从字体列表和消息和单个字符的默认路径.
SerializableJVM中的确切行为是什么?它是否始终保持"持久"副本,从而使我的内存占用量增加一倍?如何在运行时编写对象的二进制副本而无需将JVM转换为内存占用?
PS:内存消耗增加最多的方法是下面的方法.该文件每行大约有229,000行和202个字段.
public void readThetas(String filename) throws Exception
{
long t1 = System.currentTimeMillis();
documents = new HashMapX<String,double[]>(); //Document names to indices.
Scanner s = new Scanner(new File(filename));
int docIndex = 0;
if (s.hasNextLine())
System.out.println(s.nextLine()); // Consume useless first line :)
while(s.hasNextLine())
{
String[] fields = s.nextLine().split("\\s+");
String docName = fields[1];
numTopics = fields.length/2-1;
double[] thetas = new double[numTopics];
for (int i=2;i<numTopics;i=i+2)
thetas[Integer.valueOf(fields[i].trim())] = Double.valueOf(fields[i+1].trim());
documents.put(docName,thetas);
docIndex++;
if (docIndex%10000==0)
System.out.print("*"); //progress bar ;)
}
s.close();
long t2 = System.currentTimeMillis();
System.out.println("\nRead file in "+ (t2-t1) +" ms");
}
Run Code Online (Sandbox Code Playgroud)
哦!,HashMapX是一个像这样声明的内部类:
public static class HashMapX< K, V> extends HashMap<K,V> {
public V get(Object key, V altVal) {
if (this.containsKey(key))
return this.get(key);
else
return altVal;
}
}
Run Code Online (Sandbox Code Playgroud)
这可能无法解决您的所有问题,但序列化可以显着增加内存使用量:http: //java.sun.com/javase/technologies/core/basic/serializationFAQ.jsp#OutOfMemoryError.
简而言之,如果你保持ObjectOutputStream打开状态,那么除非你明确地调用它的reset()方法,否则没有任何写入它的对象可以被垃圾收集.
所以,我找到了答案。这是我的代码中的内存泄漏。与可序列化或可克隆无关。
这段代码正在尝试解析一个文件。每一行都包含一组我试图提取的值。然后,我保留其中一些值并将它们存储在 HashMapX 或其他结构中。
问题的核心就在这里:
String[] fields = s.nextLine().split("\\s+");
String docName = fields[1];
Run Code Online (Sandbox Code Playgroud)
我在这里传播它:
documents.put(docName,thetas);
Run Code Online (Sandbox Code Playgroud)
发生的情况是 docName 是对数组(字段)中元素的引用,并且我在程序的生命周期中保留该引用(通过将其存储在全局 HashMap 文档中)。只要我保持该引用处于活动状态,整个 String[] 字段就无法被垃圾收集。解决方案:
String docName = new String(fields[1]); // A copy, not a reference.
Run Code Online (Sandbox Code Playgroud)
从而复制对象并释放对数组元素的引用。这样,一旦我处理完每个字段,垃圾收集器就可以释放数组使用的内存。
我希望这对所有使用 split 解析大型文本文件并将某些字段存储在全局变量中的人有用。
感谢大家的评论。他们引导我走向正确的方向。
| 归档时间: |
|
| 查看次数: |
2280 次 |
| 最近记录: |