我找不到内存泄漏
本文关键字:泄漏 内存 找不到 | 更新日期: 2023-09-27 18:12:24
也许这不是一个很好的问题,但我有点绝望。我有一小段代码,我有一个内存泄漏,但我不知道如何克服它。请帮助。
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();
}
我将一个大的流分成更小的块,并通过sclient . sendchunk()方法将它们发送给WCF服务。假设我有一个700 mb的文件,我把它分成7个100 mb的块,然后一个接一个地发送。但是在这个方法完成后,大约有400 MB的内存,我认为这是内存泄漏。当我调试它时,我看到内存在web服务的SendChunk方法之后被chunk填充。当方法在这里结束时,我留下了内存泄漏。GC.collect()似乎也不起作用。我甚至不明白为什么700mb的文件有400mb的剩余?也许这能给我一些我不知道的线索。
任何想法?
for (int i = 0; i < nPiece + 1; i++)
{
var buffer = new byte[i != nPiece ? BufferLen : lastPieceLen];
你没有内存泄漏。你只不过是太贪吃了。您正在匆忙地吞噬内存,在for()循环中分配缓冲区。这也不是很微妙,100兆字节的缓冲区不会从天而降。任何大于85,000字节的对象都是从大对象堆中分配的,而不是从常规的分代GC堆中分配的。LOH分配不会被压缩,它们太大,并且不会被频繁收集。它需要第2代收集,它们不经常发生。
并且像这样分配有延迟效果,这就是为什么GC.Collect()没有做太多的工作来减少这个数目。你也使用了大量的RAM。Windows只有在需要的时候才会取消内存页面的映射。通常是因为另一个进程需要RAM。而且你正在吞噬大量的虚拟内存地址空间。同样,Windows内存管理器并不急于取消该空间的分配。没关系,这是虚拟的。它不需要花费任何东西。否则就不清楚你看到的是什么数字。GC.Collect()效果不大的最大原因是MemoryStream仍然有对数组的引用。调用它的Dispose()方法不会改变这一点。最后但并非最不重要的是,当您构建和运行发布版本时,抖动会删除对局部变量的空赋值。
一个简单的解决方法是重用缓冲区。在for()循环之外分配它。如果您还调整SendChunk()以接受长度参数,这将有很大帮助。简单地减少块大小,100兆字节太大了。在大多数WCF场景中,网络块大小通常最多只有1500字节。在大多数情况下,4096字节的I/O缓冲区大小是合适的。