申请泄漏字符串?

时间:2010-05-11 10:06:03

标签: .net string memory-leaks

我的.net应用程序执行了一些繁重的字符串加载/操作,不幸内存消耗不断上升和上升,当使用分析器查看它时,我看到很多未发布的字符串实例。现在在某个时间点,我确实需要所有对象都有这些字符串字段,但一旦完成,我可以摆脱例如它的一半和我Dispose()并将实例设置为null,但垃圾收集器不会选择它...它们保留在内存中(即使在处理后半小时等)。

现在如何让正确清除不需要的字符串/对象实例才能释放它们?

它们不再被引用(afaik),但是例如aspose的内存分析器说他们到gc根的距离是'3'?

更新:原始字符串来自互操作实例。这些是否可能导致泄漏?

如...分配

myClass.StringProperty = interopInstance.Description.Text;

..我的.stringProperty仍然有一个对互操作的引用,因此'泄漏'/保持interopInstance uncollected&没有正确释放/解组?

3 个答案:

答案 0 :(得分:3)

当仍然使用包含该字段的类时,将私有字段设置为null会很有用。它将允许收集引用的对象。但是,当该私有字段的实例本身未被引用时,它引用的对象也将被引用。换句话说,将对象很快取消引用的对象的空字段无效。

我认为您没有应用程序泄漏。也许您正在创建存储在大对象堆(LOH)中的字符串。当大于或等于85000字节(具有42492个字符或更多)时,对象存储在LOH中。只有当完全垃圾收集(第2代)发生时才收集LOH。因此,由于您似乎没有任何OutOfMemoryExceptions,我认为没有泄漏。您的应用程序不会耗尽内存,GC也不会收集Gen2。

您可以致电GC.Collect()进行检查。这将删除所有未使用的大对象。


因此,虽然应用程序中可能没有泄漏,但内存占用量可能不大。特别是当您编写的桌面应用程序不是唯一需要内存的应用程序时。除此之外,大量内存也可能导致性能问题,因为GC必须更频繁地运行。

也许有可能以一种使用更少内存的方式重构代码。例如,使用StringBuilder个对象(如果您还没有这样做)。或者甚至可能在池中缓存StringBuilder个对象并重用它们而不是创建一个新对象。特别是在使用从池中获取的实例时设置Capacity属性。这可能特别有用,因为LOH容易碎片化,这可能导致OutOfMemoryExceptions发生。这对于32位系统来说只是一个问题,因为64位系统几乎没有虚拟地址空间。 64位将在未来几年变得越来越主流,我相信微软还没有投入到为32位版本的CLR修复这个问题,因此。

<强> 更新 在interop的情况下,字符串被序列化和反序列化。字符串作为字节数组发送,因此通常不会更改它保持引用。但是,每次从interop获取字符串时,都会创建一个新的字节数组,而在.NET中,byte []将被复制到一个字符串中。这将使用的内存量增加一倍。

答案 1 :(得分:1)

只是对此采取行动,但你是否连接了许多字符串?如果是这样,你使用'+'运算符这样做?字符串是不可变的,这意味着每次处理时都可以在内存中创建一个新的字符串对象。

如果要连接字符串,则应考虑使用StringBuilder对象(如果您还没有这样做),甚至是String.Concat()方法。这可能是问题所在,尤其是如果您在任何时候在循环中连接字符串。

答案 2 :(得分:0)

我一直致力于在许多终端之间传输数据的系统。这些终端生成文本数据(以XML格式),然后压缩并传输到其他终端。最初我们遇到了与应用程序完全相同的问题,使用越来越多的Ram并最终耗尽内存。连接到它的终端越多,它耗尽的速度指数越快。

该系统的性能不是最重要的功能,但长期正常运行时间是。

在通过剖析器搜寻以找到记忆消失的地方后,我们发现如果其中有任何实质内容,我们的字符串最终会在LOH中结束。

我知道这是有争议的,许多人说不要强迫GC.Collect,但我也发现其他网站,例如Rico Mariani,如果你有特殊需求,你确定你的对象最终在LOH然后继续做,只记得GC.Collect会影响性能。

好消息是,一旦我们将这个添加到程序的字符串处理区域,我们就会在应用程序的整个生命周期中使用相同的ram使用情况,并且我们运行的一些系统具有正常运行时间&GT;60天