-1

我正在开发一个使用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();
4

4 回答 4

4

您当前正在将整个文件读入内存,即使您只想将其复制到另一个流。不要那样做。一次只迭代一个块:读取一个块,写入一个块,读取一个块,写入一个块等。如果您使用的是 .NET 4,则可以Stream.CopyTo用于此目的。

于 2012-11-25T19:13:11.827 回答
3

您正在缓冲您的读取,但不是您的写入。该程序正在按照您的要求执行 - 分配一个巨大的块或内存并在发送单个字节之前将其全部填充。

更好的方法是从文件中读取一个小块(为了参数,4096 字节),然后将该块写入输出流。通过这样做,每个连接将只使用 4096 字节,这更具可扩展性。

于 2012-11-25T19:13:22.097 回答
1

当您的系统内存不足或在 32 位进程中您的地址空间不足 (2000MB) 时,通常会发生 OOM 情况。

你说它可以成功复制一个但不能复制两个?这两个是同时的还是连续的?你的线程模型是什么?另外,这个例子是一个片段,你似乎有一个 StreamWriter 和一个 Stream 用于写入,这些对象会消失吗?

小心 GC.Collect。Microsoft 不推荐显式调用,因为如果您没有正确使用它,它可能会导致对象的存活时间超过所需时间。这是因为当您执行 GC.Collect 时,您将对象提升到更高的一代。根据我的经验,最好确保您正在释放对象并让框架决定 GC.Collect 的内容/时间。

我会熟悉 WinDBG+SOS,这使您可以查看堆上的对象。

尝试这个:

  1. 启动 WinDBG 并附加到您的进程
  2. 如果使用 4.0,请输入“.loadby sos clr”,否则输入“.loadby sos mscorwks”
  3. 按 F5 继续
  4. 复制一个文件,等待它完成
  5. 按 CTRL+BREAK
  6. 输入“!dumpheap -stat”,查看结果,寻找应该消失的对象
  7. For-Each 应该消失的对象,获取 MT 值
  8. 键入“!dumpheap -mt {0}”,将 {0} 替换为上述步骤中的值
  9. 这是一个实例列表,抓取其中一个对象地址
  10. 键入“!gcroot {0}”将 {0} 替换为对象地址

这应该告诉您什么是对象的根,然后您需要找出如何取消根,例如不需要的空对象。

于 2012-11-25T20:08:37.853 回答
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);
   }
于 2012-11-25T19:28:49.357 回答