簡體   English   中英

下載視頻文件時出現 Memory 異常

[英]Out Of Memory Exception when downloading a video file

我們目前從 Twilio 下載視頻,下載視頻后,我們將視頻保存在AWS S3中。 但是,在部署到生產環境時,我目前得到:

引發了“System.OutOfMemoryException”類型的異常。

嘗試下載視頻時,

我檢查了 Twilio 中的視頻大小,它們相對較小,172,912kb

我已將 S3 上的實例升級到大型實例,因為我認為這將是一個問題,因為在它們很小之前。

但是問題仍然存在,它失敗的代碼塊如下:

 var request = (HttpWebRequest)WebRequest.Create($"{resource.Url}/Media");
 request.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(Encoding.ASCII.GetBytes(_twilioOptions.ApiKey + ":" + _twilioOptions.ApiSecret)));
 request.AllowAutoRedirect = true;

 var responseBody = (request.GetResponseAsync().Result).GetResponseStream();

 byte[] tempBuffer = new byte[8192];
 MemoryStream ms = new MemoryStream();
 int read;
 while ((read = responseBody.Read(tempBuffer, 0, tempBuffer.Length)) > 0)
 {
    ms.Write(tempBuffer, 0, read);
 }

 var result = ms;
    
 var fileName = $"Conversations/{conversationId}/Video-{DateTime.UtcNow:yyyyMMdd-hhmmss}-{compositionSid}.{resource.Format}";
 var uploadedFile = await _fileUploader.UploadFile(result, fileName, _s3Options.SecureBucket, "video/mp4");

任何人都可以為此推薦解決方案/修復程序嗎?

從理論上講,在S37GB RAM計划)上一次將 ~170MB 文件下載到 memory 應該沒有問題。 但是,您不會處置或關閉任何資源。 根據周圍的代碼,這很可能是未釋放非托管資源的問題,並可能導致 memory 在一段時間內用完。

現在我們可以對Close()Dispose()進行顯式調用,但更容易將相關代碼封裝在using()塊中,如下所示:

 
 byte[] tempBuffer = new byte[8192];
 using (var responseBody = (request.GetResponseAsync().Result).GetResponseStream()) 
 using (var ms = new MemoryStream()) // <------- using block, will call Dispose() 
 {
     int read;
     while ((read = responseBody.Read(tempBuffer, 0, tempBuffer.Length)) > 0)
     {
        ms.Write(tempBuffer, 0, read);
     }

     var result = ms;
    
     var fileName = $"Conversations/{conversationId}/Video-{DateTime.UtcNow:yyyyMMdd-hhmmss}-{compositionSid}.{resource.Format}";
     var uploadedFile = await _fileUploader.UploadFile(result, fileName, 
                                                      _s3Options.SecureBucket, "video/mp4");
}


您的代碼類似於MSDN 示例,但是您會注意到Close()的使用。

告訴我更多

感謝 mjwills 發現responseBody也可以放入using()塊中,從而節省顯式Close

往前走

即使有了這些修復,您也可能希望利用流式資源的最佳實踐,而不是一次全部加載,尤其是在不需要一次將其全部加載到 memory 的情況下。 只需為源創建一個讀取 stream 並為目標創建一個寫入 stream。 然后它只是一次讀取和寫入塊的問題。

正如您可能已經猜到的那樣,將整個視頻保存在 memory 中是一個壞主意,如果它很大的話。

盡管 180mb 看起來並不多,但它仍然需要一個連貫的 memory 區域用於 LOH 中。 使用某些將塊寫入磁盤的方法可能會更好。 為了提高性能和避免 LOH 中的 memory 碎片,您也可以順便使用RecyclableMemoryStream ,但這對您當前的系統沒有任何作用。

通常你應該避免這種設計。 要么保存到磁盤(使用 memory 緩沖)並信任小文件的文件系統緩存,要么嘗試直接將下游饋送到上游。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM