0

Maybe this is not a good question to post but I am kinda desperate. I have a little piece of code, and i have a memory leak, but i don't know how to overcome it. please help.

        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();
        }

I split a large stream into smaller chunks and send them to a WCF service over SsClient.SendChunk() method. Let's say I have a file which is 700 mb, i split it into 7 pieces of 100 mb chunks, and send them one by one. but after this method is done there is around 400 mb in memory which i see as memory leak. when i debug it i see memory gets filled with chunk right after SendChunk method of web service. When the method finished here I'm left with the memory leak. GC.collect() doesn't seem to work either. I didn't even understand why there is 400 mb leftover of 700 mb file? maybe that might give some clues i don't know.

any ideas?

4

1 回答 1

3
    for (int i = 0; i < nPiece + 1; i++)
    {
         var buffer = new byte[i != nPiece ? BufferLen : lastPieceLen];

你没有内存泄漏。你只是有一个坏情况的零食。您正在匆忙地吞噬内存,在 for() 循环内分配缓冲区。它也不是微妙的,100 兆字节的缓冲区不会从天而降。任何大于 85,000 字节的对象都是从大对象堆分配的,而不是常规的分代 GC 堆。LOH 分配不会被压缩,它们太大,并且不会被频繁收集。它需要一个 gen #2 集合,它们不会经常发生。

并且像这样分配会产生延迟效果,因为您看不到 GC.Collect() 对减少数量有多大作用。您还使用了大量的 RAM。除非必须,否则 Windows 不会取消映射内存页面。通常是因为另一个进程需要 RAM。而且你正在吞噬大量的虚拟内存地址空间。同样,Windows 内存管理器并不急于取消分配该空间。没关系,它是虚拟的。它不需要任何费用。否则不清楚你在看什么数字。GC.Collect() 影响不大的最大原因是因为 MemoryStream 仍然有对数组的引用。调用它的 Dispose() 方法并不会改变这一点。最后但并非最不重要的一点是,当您构建和运行发布版本时,抖动会删除对局部变量的空分配。

一个简单的解决方法是重新使用缓冲区。将其分配到 for() 循环之外。如果您还调整 SendChunk() 以采用长度参数,这将有很大帮助。并且简单地减少块大小,100 兆字节太多了。这在大多数 WCF 场景中通过网络进行,网络块大小通常最多只有 1500 字节。在大多数情况下,4096 字节的 I/O 缓冲区大小是正确的。

于 2013-05-05T20:43:47.877 回答