2016-10-11 46 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

感謝您的鏈接,相當有用。 –

相關問題