【问题标题】:HttpClient throws OutOfMemory exception when TransferEncodingChunked is not set未设置 TransferEncodingChunked 时 HttpClient 抛出 OutOfMemory 异常
【发布时间】:2017-02-19 18:50:22
【问题描述】:

为了支持上传带有进度报告的大型(实际上非​​常大,最多几 GB)文件,我们开始使用带有 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 的文档,这更像是一个试验和失败的过程,但在这种情况下它似乎至关重要。我仍然很困惑为什么会抛出异常 - 内存消耗不是很高,是什么原因造成的?

【问题讨论】:

  • 好吧,如果数据很大,最好分块发送,你觉得奇怪吗?
  • 我发现这么早就提出了令人惊讶的 OutOfMemory 异常。

标签: c# upload httpclient large-files


【解决方案1】:

Chunked transfer encoding

分块传输编码是 1.1 版本中的一种数据传输机制 超文本传输​​协议 (HTTP),其中数据以 一系列“块”。它使用了 Transfer-Encoding HTTP 标头 的 Content-Length 标头,它的早期版本 否则协议将需要。1 因为 Content-Length 标头 不使用,发送者不需要知道长度 在它开始向接收器发送响应之前的内容。 发件人可以在之前开始传输动态生成的内容 知道该内容的总大小。

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

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

【讨论】:

  • 这是有道理的,并解释了为什么内存消耗会下降。仍然奇怪的是 OutOfMemory 异常被抛出。如果我不使用 PushStreamContent 并坚持使用由 HttpClient 完全控制的传统 StreamContent,则不会引发异常。
  • @VagifAbilov 我不能告诉你为什么,这需要研究,这是一个不同的问题。你可以检查这个问题:stackoverflow.com/questions/16168683/…。几乎他们说当您需要将数据推送到流时使用推送流内容,当您需要从流中提取时使用流内容。
  • 感谢链接,很有用。
猜你喜欢
  • 2012-01-14
  • 2015-12-04
  • 2019-07-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多