未设置TransferEncodingChunked时,HttpClient会抛出OutOfMemory异常

时间:2016-10-11 08:57:33

标签: c# upload httpclient large-files

为了支持使用进度报告上传大型(实际上非​​常大,高达几千兆字节)的文件,我们开始使用带有PushStreamContent的HttpClient,如here所述。它工作简单,我们在两个流之间复制字节,这是一个代码示例:

    private void PushContent(Stream src, Stream dest, int length)
    {
        const int bufferLength = 1024*1024*10;
        var buffer = new byte[bufferLength];
        var pos = 0;
        while (pos < length)
        {
            var bytes = Math.Min(bufferLength, length - pos);
            src.Read(buffer, 0, bytes);
            dest.Write(buffer, 0, bytes);
            pos += bufferLength;
            dest.Flush();
            Console.WriteLine($"Transferred {pos} bytes");
        }
        dest.Close();
    }

但是在开始时,这个代码在传输320 MB之后引发了OutOfMemory异常,即使进程的内存消耗不是很高(大约500 MB)。修复此问题的原因是设置TransferEncodingChunked标志:

request.Headers.TransferEncodingChunked = true;

不仅我们能够在设置了这个标志的情况下传输大文件,内存消耗也减少了90%。

我没有找到任何需要使用TransferEncodingChunked的文档,它更像是一个试验和失败的过程,但在这种情况下似乎至关重要。我仍然感到疑惑为什么会抛出异常 - 内存消耗不是很高,是什么原因导致的?

1 个答案:

答案 0 :(得分:4)

Chunked transfer encoding

  

Chunked transfer encoding是1.1版中的数据传输机制   超文本传输​​协议(HTTP)中的数据发送方式   系列&#34; chunks&#34;。它使用Transfer-Encoding HTTP标头   Content-Length标头,它的早期版本   否则协议将需要。1因为Content-Length标头   没有使用,发件人不需要知道的长度   在开始向接收者发送响应之前的内容。   发件人之前可以开始传输动态生成的内容   知道该内容的总大小。

     

每个块的大小都是在块本身之前发送的   接收器可以告诉它何时完成接收数据   块。数据传输由最后一块长度终止   零。

如果我们从逻辑上思考,文件是在小块上发送的,这意味着当你完成一个块时,你就可以将它从内存中释放出来。最后,您可以减少内存消耗,因为您正在处理多个小块。