我一直在跟踪我的应用程序中的大量内存泄露,似乎问题是MemoryStream类。每当我使用一个,使用'using'关键字或显式关闭/ dispose时,垃圾收集器永远不会收集内存。这有什么不对?
byte[] bData = System.IO.File.ReadAllBytes( "F:\\application_exit_bw.png" );
using( System.IO.MemoryStream hMemoryStreamOutput = new System.IO.MemoryStream())
{
for ( int i = 0; i < 10000; i++ ) hMemoryStreamOutput.Write( bData, 0, bData.Length );
}
Thread.Sleep(Timeout.Infinite);
使用显式关闭/ dipose,行为保持不变。内存被占用并将保持这种状态,直到我关闭我的应用程序,或者,应用程序填满了所有系统内存。帮助
答案 0 :(得分:7)
MemoryStream
类或示例代码中的用法没有任何问题。不再有.Net中的GC不会立即清理内存。相反,当堆中的可用空间达到某个阈值或通过GC.Collect
调用显式调用时,它会回收它。
在这种情况下,释放内存的唯一方法是在using
语句之后和Thread.Sleep
调用之前立即发生GC。这是不太可能发生的,因此如果您对程序进行了分析,当它实际上没有泄漏时会出现内存泄漏
答案 1 :(得分:5)
这是非确定性GC的症状。 GC不会对任何保证何时释放内存。这是正常的,预期的和想要的行为。
尝试调用GC.Collect()以查看是否可以解决您的问题。此外,您需要在发布模式下运行,因为在调试模式下,JIT会将局部变量的生命周期延长到方法的末尾,即使它们在某个点之后未被使用也是如此。
答案 2 :(得分:1)
问题的另一方面是您正在使用什么来确定“内存泄漏”。有许多不同的方法来衡量“免费”记忆,依赖于它,你可能得到完全不同的结果。
MemoryStream(以及任何其他大型86K +)分配还有一件事 - 它们使用仅在完整GC上收集的大对象堆,触发它可能需要运行GC.Collect两次。在应用程序的正常流程中,它将足够重复,因此您可能无法在应用程序关闭之前释放此内存。诊断 - 检查GC收集性能计数器(GC的数量)。
还有一个:如果你正在尝试解决内存泄漏,因为你遇到“内存不足”异常,可能是由地址空间碎片引起的(通常只有32位进程)。如果是这种情况 - 考虑创建自己的内存流,不在单个块中分配内存,然后在增长流时必须复制它。或者至少尝试预先分配流中的空间。
答案 3 :(得分:0)
我已将此方法用于批处理
static byte[] buffer;
public static object Read(XmlDocument xmlDocument)
{
if (buffer == null)
{
buffer = new byte[1024 * 1024 * 512];
}
if (xmlDocument != null)
{
using (MemoryStream ms = new MemoryStream(buffer))
{
xmlDocument.Save(ms);
ms.Flush();
ms.Seek(0, SeekOrigin.Begin);
object result = ReadFromStream(ms);
ms.Close();
return result;
}
}
else
{
return null;
}
}
答案 4 :(得分:0)
调用GC.Collect()不是一个好习惯,不应该用作解决方案。
您可以尝试查看是否有任何改变,但不依赖于故意GC.Collect()调用......