也许这不是一个好问题,但我有点绝望。我有一小段代码,我有内存泄漏,但我不知道如何克服它。请帮忙。
var nPiece = stream.Length / BufferLen;
var lastPieceLen = stream.Length - (nPiece * BufferLen);
for (int i = 0; i < nPiece + 1; i++)
{
var buffer = new byte[i != nPiece ? BufferLen : lastPieceLen];
stream.Read(buffer, 0, buffer.Length);
using (var chunk = new MemoryStream(buffer))
SsClient.SendChunk(i != nPiece ? (i + 1).ToString() : ((i + 1) + "last"), SsSession, chunk);
buffer = null;
GC.Collect();
}
我将一个大型流拆分为较小的块,并通过SsClient.SendChunk()方法将它们发送到WCF服务。让我们说我有一个700 MB的文件,我把它分成7块100 MB的块,并逐个发送。但是在这个方法完成后,内存大约有400 MB,我认为是内存泄漏。当我调试它时,我看到内存充满了网络服务的SendChunk方法后的块。当方法在这里完成时,我留下了内存泄漏。 GC.collect()似乎也不起作用。我甚至不明白为什么有400 MB的文件剩余400 MB?也许这可能会给我一些我不知道的线索。
任何想法?
答案 0 :(得分:3)
for (int i = 0; i < nPiece + 1; i++)
{
var buffer = new byte[i != nPiece ? BufferLen : lastPieceLen];
您没有内存泄漏。你只是得到了一个关于零食的坏情况。你匆忙地吞噬内存,在for()循环中分配缓冲区。它也不是微妙的,100兆的缓冲区不会从天而降。从大对象堆分配大于85,000字节的任何对象,而不是常规的分代GC堆。 LOH分配不会被压缩,它们太大,并且不会经常收集。它需要第2代第2集,它们并不经常发生。
如此分配会产生延迟效果,因此您没有看到GC.Collect()会减少数量。你也使用了很多内存。 Windows必须先取消映射内存页面。通常因为另一个进程需要RAM。而且你正在吞噬大量的虚拟内存地址空间。 Windows内存管理器也不急于取消分配该空间。哪个没关系,它是虚拟的。它不需要任何费用。否则你不清楚你在看什么号码。 GC.Collect()影响不大的最大原因是因为MemoryStream仍然有对数组的引用。调用它的Dispose()方法不会改变它。最后但同样重要的是,当您构建并运行Release版本时,抖动会删除对本地变量的null赋值。
一个简单的解决方法是重新使用缓冲区。在for()循环之外分配它。如果您还调整SendChunk()以获取长度参数,它将会有很大帮助。而简单地减少块大小,100兆就太多了。这在大多数WCF场景中通过网络进行,网络块大小通常仅为1500字节。在大多数情况下,I / O的缓冲区大小约为4096字节。