2016-10-11 37 views
3

为了支持大量的上传(实际上非​​常大,高达数千兆字节)的文件与进度报告,我们开始使用的HttpClient与PushStreamContent,如所描述here。它的工作原理简单,我们两个流之间复制字节,这里是一个代码示例:的HttpClient抛出OutOfMemory例外时TransferEncodingChunked未设置

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,即使进程的内存消耗不是非常高后引发内存溢出的例外(大约500 MB)。什么固定的这个问题是设置TransferEncodingChunked标志:

request.Headers.TransferEncodingChunked = true; 

我们不仅能够转移具有这个标志巨大的文件,内存消耗下降了90%。

我还没有找到任何需要使用TransferEncodingChunked的文档,它更像是一个试验和失败的过程,但在这种情况下似乎很重要。尽管如此,我仍然困惑于为什么抛出异常 - 内存消耗不是很高,是什么原因造成的?

+0

那么,如果数据量很大,最好是将它发送成块,你会发现那令人惊讶吗? – demonplus

+0

我发现这么早就引起了令人惊讶的OutOfMemory异常。 –

回答

3

Chunked transfer encoding

块传输编码处于其中数据以 系列“块”的发送的超文本传输​​协议(HTTP)的版本1.1 一个数据传输机制。它使用Content-Length头的 的Transfer-Encoding HTTP头,这是 协议的早期版本另外需要的地方。 1由于未使用内容长度标头 ,发送方在开始向接收方发送响应之前不需要知道内容的长度。 发件人可以在 知道该内容的总大小之前开始传输动态生成的内容。

每个块的大小恰好在块本身之前发送,因此接收器可以告知 何时它已经完成接收该块 的数据。数据传输终止于长度为 零的最后一个块。

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

+0

这是有道理的,并解释了为什么内存消耗下降。仍然很奇怪OutOfMemory异常被抛出。如果我不使用PushStreamContent并坚持使用完全由HttpClient控制的传统StreamContent,则不会引发异常。 –

+1

@VagifAbilov我不能告诉你为什么,这需要研究,这是一个不同的问题。你可以检查这个问题:http://stackoverflow.com/questions/16168683/webapi-streamcontent-vs-pushstreamcontent。他们说,当你需要将数据推送到数据流时,推送流内容正在使用,当你需要从数据流中提取数据时,推送流内容正在使用。 – mybirthname

+0

感谢您的链接,相当有用。 –

相关问题