使用HttpWebRequest流传输大文件时出现内存不足异常

8

当使用Http.Put上传大文件时,我会遇到内存不足异常。我正在使用如下代码所示的异步模型。我试图将8K数据块发送到Windows 2008 R2服务器。当我尝试写入超过536,868,864字节的数据块时,异常始终发生。在下面的代码片段中,异常发生在requestStream.Write方法上。

为什么会出现这种情况呢?

注意:较小的文件可以正常上传。如果我写入本地FileStream,则逻辑也能正常工作。客户端计算机上运行VS 2010、.Net 4.0和Win 7 Ultimate操作系统。

   HttpWebRequest request = (HttpWebRequest)WebRequest.Create("Http://website/FileServer/filename");
   request.Method = WebRequestMethods.Http.Put;
   request.SendChunked = true;
   request.AllowWriteStreamBuffering = true;
   ...

   request.BeginGetRequestStream( new AsyncCallback(EndGetStreamCallback), state);
   ...

   int chunk = 8192; // other values give same result
   ....

   private static void EndGetStreamCallback(IAsyncResult ar) {
        long limit = 0;
        long fileLength;
        HttpState state = (HttpState)ar.AsyncState;

        Stream requestStream = null;
        // End the asynchronous call to get the request stream.

        try {
            requestStream = state.Request.EndGetRequestStream(ar);
            // Copy the file contents to the request stream.

            FileStream stream = new FileStream(state.FileName, FileMode.Open, FileAccess.Read, FileShare.None, chunk, FileOptions.SequentialScan);

            BinaryReader binReader = new BinaryReader(stream);
            fileLength = stream.Length;

            // Set Position to the beginning of the stream.
            binReader.BaseStream.Position = 0;

            byte[] fileContents = new byte[chunk];

            // Read File from Buffer 
            while (limit < fileLength)
            {
                fileContents = binReader.ReadBytes(chunk);

                // the next 2 lines attempt to write to network and server
                requestStream.Write(fileContents, 0, chunk);   // causes Out of memory after 536,868,864 bytes
                requestStream.Flush();  // I get same result with or without Flush

                limit += chunk;
            }

            // IMPORTANT: Close the request stream before sending the request.
            stream.Close();

            requestStream.Close();
        }
    }

1
POST请求也是这样吗?你的代码实际上发送了任何数据吗? - svick
你可能想了解一下.NET 4中针对流的新CopyTo()方法。 - Cameron
1个回答

18
你似乎已经遇到这个已记录的问题。当AllowWriteStreamBuffering设置为true时,它会缓存写入请求的所有数据! 因此,“解决方案”是将该属性设置为false

要解决此问题,请将HttpWebRequest.AllowWriteStreamBuffering属性设置为false。


1
文档中也提到:“将AllowWriteStreamBuffering设置为true可能会在上传大型数据集时导致性能问题,因为数据缓冲区可能会使用所有可用内存。” - svick
是的,我们尝试过这个,但仍然在将其设置为true或false方面遇到挑战。我认为真正的解决方案是不使用PUT或POST进行更新,而是使用更低级别的技术,如WCF或POS(Plain Ole Sockets lol)。 - pearcewg
如果您找到一种确保其正常工作的方法,请在问题(或您自己的答案)中添加更新!我也很好奇,将来可以参考这个参考资料。;-) - Cameron
我们最终放弃了这个方案,并用WCF上传取而代之,效果非常好!我建议您考虑同样的解决方案。 - pearcewg
@pearcewg:很酷,好知道。谢谢!你用了哪个类? - Cameron
非常棒的答案。我成功地从运行在Xamarin Forms上的512M RAM设备上传了一个600M的文件。如果没有这个设置,它会在上传到20%左右时崩溃。 - root

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接