簡體   English   中英

ASP.NET MVC / WEB API文件上載:上載后內存未被釋放

[英]ASP.NET MVC/WEB API File Upload: Memory not being deallocated after upload

我正在研究用戶上傳文件的項目可能存在的內存泄漏問題。 這些文件通常是.zip或.exe壓縮文件,用於其他軟件。 文件的平均大小為80MB

有一個MVC應用程序,它具有上傳文件的界面(View)。 此視圖向控制器內的操作發送POST請求。 此控制器操作使用與此類似的MultipartFormDataContent獲取文件: 發送二進制數據以及REST API請求,並且: WEB API文件上傳,單個或多個文件

在操作中,我獲取文件並將其轉換為字節數組。 轉換后,我使用byte []數組向我的API發送一個post請求。

這是執行該操作的MVC APP代碼:

[HttpPost]
    public async Task<ActionResult> Create(ReaderCreateViewModel model)
    {
        HttpPostedFileBase file = Request.Files["Upload"];

        string fileName = file.FileName;

        using (var client = new HttpClient())
        {
            using (var content = new MultipartFormDataContent())
            {                   
                using (var binaryReader = new BinaryReader(file.InputStream))
                {
                    model.File = binaryReader.ReadBytes(file.ContentLength);
                }

                var fileContent = new ByteArrayContent(model.File);
                fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
                {
                    FileName = file.FileName
                };
                content.Add(fileContent);

                var requestUri = "http://localhost:52970/api/upload";
                HttpResponseMessage response = client.PostAsync(requestUri, content).Result;

                if (response.IsSuccessStatusCode)
                {                       
                    return RedirectToAction("Index");
                }
            }
        }

        return View("Index", model);
    }

在調查使用如下的幾個內存工具之后: 最佳實踐5:檢測.NET應用程序內存泄漏我發現在將此文件轉換為此行的字節數組之后:

using (var binaryReader = new BinaryReader(file.InputStream))
{
      model.File = binaryReader.ReadBytes(file.ContentLength);
}

內存使用量從70MB +或 - 增加到175mb +或 - 甚至在發送和完成請求后,內存永遠不會被釋放。 如果我繼續上傳文件,內存會不斷增加,直到服務器完全關閉。

我們無法將文件直接從多部分表單發送到API,因為我們需要先發送和驗證一些數據(業務需求/規則)。 經過研究,我采用了這種方法,但內存泄漏問題與我有關。

我錯過了什么嗎? 垃圾收集器應該立即收集內存嗎? 在所有一次性對象中,我使用的是“使用”語法,但它沒有幫助。

我也很好奇這種上傳文件的方法。 我應該以不同的方式做嗎?

只是為了澄清,API與MVC應用程序分離(每個應用程序都托管在IIS中的一個獨立的網站上),它全部都在C#中。

1.垃圾收集器是否應立即收集內存?

垃圾收集器不會立即釋放內存,因為這是一個非常耗時的操作。 發生垃圾收集時,將暫停所有應用程序的托管線程。 這會引入不必要的延遲 因此,垃圾收集器僅基於復雜的算法偶爾執行。

2.在所有一次性對象中,我使用的是“使用”語法,但它沒有幫助。

using語句處理有限供應的非托管資源(通常與IO相關,如文件句柄,數據庫和網絡連接)。 因此,此語句不會影響垃圾回收。

我錯過了什么嗎?

在用ByteArrayContent包裝它之后,看起來你不需要原始的字節數組。 在包裝之后你不會清理model.File ,並且數組最終可以傳遞給Index視圖。

我會替換:

using(var binaryReader = new BinaryReader(file.InputStream)) {
    model.File = binaryReader.ReadBytes(file.ContentLength);
}
var fileContent = new ByteArrayContent(model.File);

有:

ByteArrayContent fileContent = null;
using(var binaryReader = new BinaryReader(file.InputStream)) {
    fileContent = new ByteArrayContent(binaryReader.ReadBytes(file.ContentLength));
}

避免需要清理model.File 。明確表示文件。

4.如果我繼續上傳文件,內存會不斷增加,直到服務器完全關閉。

如果您的文件平均為80MB,則它們最終會出現在大對象堆上。 堆不會自動壓縮,通常不會被垃圾回收。 看起來在你的情況下,大對象堆無限增長(可能會發生)。

如果您正在使用(或可以升級到).NET 4.5.1或更高版本,則可以通過設置來強制壓縮大對象堆:

System.Runtime.GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;

每次要在下一個完整垃圾回收集中調度大對象堆壓縮時,都需要調用此行代碼。

您還可以通過調用強制立即壓縮:

System.Runtime.GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
System.GC.Collect();

但是,如果您需要釋放大量內存,那么就時間而言,這將是一項代價高昂的操作。

暫無
暫無

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

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