我正在使用TCP
通过网络发送/接收文件的程序。
程序发送多个文件,因此在用户退出程序之前,流不会关闭。
我面临的问题是,当我发送700mb文件时,我的服务器程序私有内存增长到700,000 K并严重削弱了我的计算机性能。当尝试发送另一个700mb文件时,服务器会抛出System.OutOfMemoryException
。
有人可以告诉我我做错了什么,或者没做错?
服务器端代码:
using ( FileStream fs = new FileStream("dracula.avi", FileMode.Open, FileAccess.Read))
{
byte[] data = new byte[fs.Length];
int remaining = data.Length;
int offset = 0;
strWriter.WriteLine("Content-Length: " + data.Length);
strWriter.Flush();
Thread.Sleep(1000);
while (remaining > 0)
{
Thread.Sleep(10);
int read = fs.Read(data, offset, remaining);
remaining -= read;
offset += read;
}
fs.Flush();
fs.Close();
}
strm.Write(data, 0, data.Length);
strm.Flush();
GC.Collect();
答案 0 :(得分:4)
您当前正在将整个文件读入内存,即使您只想将其复制到另一个流中。不要那样做。只需一次迭代一个块:读取一个块,写一个块,读一个块,写一个块等等。如果你使用的是.NET 4,你可以使用Stream.CopyTo
来实现这个目的。
答案 1 :(得分:3)
你正在缓冲你的阅读,但不是你的写作。该程序正在完成您所告知的操作 - 在发送单个字节之前分配一个巨大的块或内存并填充所有内容。
更好的方法是从文件中读取一小块(为了参数,4096字节),然后将块写入输出流。通过这样做,每个连接只能使用4096个字节,这样可以扩展得更多。
答案 2 :(得分:1)
最好在阅读后立即发送数据块。我没有测试代码,但它应该类似于;
var bufferLenght = 1024;
byte[] buffer;
while (remaining > 0)
{
buffer = new byte[1024];
int len = fs.Read(buffer, offset, bufferLenght);
remaining -= len;
offset += len;
strm.Write(buffer, 0, len);
}
答案 3 :(得分:1)
当您用完系统内存时,或者在32位进程中,您的地址空间不足(2000MB)时,通常会出现OOM情况。
你说它可以成功复制一个而不是两个吗?这两个是同时还是连续?你的线程模型是什么?此外,该示例是一个片段,您似乎有一个StreamWriter和一个用于写入的Stream,这些对象是否会消失?
小心GC.Collect。 Microsoft不建议显式调用,因为如果您不正确使用它,它可能导致对象保持活动的时间超过需要。这是因为当您执行GC.Collect时,您正在将对象提升为更高代。根据我的经验,最好确保释放对象并让框架决定GC.Collect的时间/时间。
我会熟悉WinDBG + SOS,这允许你查看堆上的对象。
试试这个:
这应该告诉你什么是对象的根源,然后你需要找出如何取消根,例如,空对象不需要。