未设置 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 报告中显示为(未设置)/(未设置)
C# MongoDbDriver - 未设置,无法使其未设置数据库中的字段
PyVmomi 添加带有未连接 dvs 的 NIC('config.distributedVirtualSwitch' 未设置)