我在解析器中发现内存泄漏。我不知道如何解决这个问题。 让我们看看基本路由。
private void parsePage() {
String[] tmp = null;
foreach (String row in rows) {
tmp = row.Split(new []{" "}, StringSplitOptions.None);
PrivateRow t = new PrivateRow();
t.Field1 = tmp[1];
t.Field2 = tmp[2];
t.Field3 = tmp[3];
t.Field4 = String.Join(" ", tmp);
myBigCollection.Add(t);
}
}
private void parseFromFile() {
String[] tmp = null;
foreach (String row in rows) {
PrivateRow t = new PrivateRow();
t.Field1 = "mystring1";
t.Field2 = "mystring2222";
t.Field3 = "mystring3333";
t.Field4 = "mystring1 xxx yy zzz";
myBigCollection.Add(t);
}
}
在集合上启动 parsePage()(行是100000个元素的列表)使我的应用程序从20MB增长到70MB。
启动 parseFromFile(),从文件读取SAME集合,但避免拆分/加入,大约需要1MB。
使用MemoryProfiler,我看到" t" fields和PrivateRow ,kkep引用String.Split()数组和Split.Join。 我想这是因为我分配了一个可以被垃圾收集的引用而不是副本。
好吧,使用70mb并不是什么大不了的事,但是当我开始制作时,有很多网站,它可以提高2.5-3GB ......
干杯
答案 0 :(得分:3)
这本身并不是内存泄漏。它实际上表现得很好。你的第二个函数使用如此少的内存的原因,仅仅是因为你只使用了四个字符串。这四个字符串中的每一个只分配一次,后续使用新t.Fieldx实例的字符串实际上引用相同的字符串值。字符串是不可变的,因此如果您多次引用相同的字符串值,它可以由相同的字符串实例处理。有关详细信息,请参阅this article on String in .NET上标有“实习”的段落。
在你的第一个函数中,每个字段都有大部分不同的字符串,每次循环都有。这只是更加多样化的数据。只要您的PrivateRow对象存在,这些字符串保留的事实就是您希望发生的事情。
答案 1 :(得分:2)
你根本没有内存泄漏,只是垃圾收集器需要时间来处理它。
我想这是因为我可以分配一个引用,而不是一个副本 被垃圾收集。
这是不正确的假设。在分配期间复制string
,即使它是引用类型。它是BCL内部的特殊,种类,独特的类型。
如果您有严重的内存压力,那么可能的解决方案呢?如果您要从文件中处理大量字符串,则可以查看2个选项。
1)通过读取srteam(不是一次加载)按顺序处理它们。在内存中尽可能少地加载/需要/生成。
2)再次使用MemoryMappedFile加载数据块并按顺序处理它们。
第二名可以与第一名合并。
答案 2 :(得分:0)
话虽如此,您可以采取一些措施来帮助降低内存使用率或更快地恢复内存:
1)您应该能够替换
t.Field4 = String.Join(" ", tmp);
带
t.Field4 = row;
您通过拆分tmp
创建了row
,然后又将其重新加入。{1}}。避免仅使用row
创建新字符串。
2)在方法结束时调用GC.Collect();
以请求立即进行垃圾回收。这不会减少方法中使用的内存,但应该更快地释放内存。
答案 3 :(得分:-5)
如果您的应用程序对内存使用至关重要并且有大量重复数据,则应使用枚举替换字符串值。