未设置 TransferEncodingChunked 时 HttpClient 抛出 OutOfMemory 异常

Posted

技术标签:

【中文标题】未设置 TransferEncodingChunked 时 HttpClient 抛出 OutOfMemory 异常【英文标题】:HttpClient throws OutOfMemory exception when TransferEncodingChunked is not set 【发布时间】: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 异常。 【参考方案1】:

Chunked transfer encoding

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

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

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

【讨论】:

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

以上是关于未设置 TransferEncodingChunked 时 HttpClient 抛出 OutOfMemory 异常的主要内容,如果未能解决你的问题,请参考以下文章

google / cpc 会话在 Google Analytics(分析)的 Source / Medium 报告中显示为(未设置)/(未设置)

有没有办法区分未设置的属性和设置为未定义的属性? [复制]

无法设置未定义或null引用的属性“onclick”

C# MongoDbDriver - 未设置,无法使其未设置数据库中的字段

PyVmomi 添加带有未连接 dvs 的 NIC('config.distributedVirtualSwitch' 未设置)

未捕获的类型错误:无法设置未定义的属性 [重复]