C# ASP.NET MVC/WEB API文件上载:上载后未释放内存
我正在调查一个用户上载文件的项目中可能存在的内存泄漏问题。这些文件通常是用于其他软件的.zip或.exe压缩文件。文件的平均大小为80MB 有一个MVC应用程序,它具有上载文件(视图)的界面。此视图向控制器内的操作发送POST请求。此控制器操作使用与以下内容类似的MultipartFormDataContent获取文件: 在操作内部,我获取文件并将其转换为字节数组。转换后,我用byte[]数组向API发送post请求 以下是实现此功能的MVC应用程序代码:C# ASP.NET MVC/WEB API文件上载:上载后未释放内存,c#,asp.net-mvc,file-upload,asp.net-web-api,memory-leaks,C#,Asp.net Mvc,File Upload,Asp.net Web Api,Memory Leaks,我正在调查一个用户上载文件的项目中可能存在的内存泄漏问题。这些文件通常是用于其他软件的.zip或.exe压缩文件。文件的平均大小为80MB 有一个MVC应用程序,它具有上载文件(视图)的界面。此视图向控制器内的操作发送POST请求。此控制器操作使用与以下内容类似的MultipartFormDataContent获取文件: 在操作内部,我获取文件并将其转换为字节数组。转换后,我用byte[]数组向API发送post请求 以下是实现此功能的MVC应用程序代码: [HttpPost] publ
[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);
}
内存使用量从70MB+或-增加到175mb+或-甚至在发送和完成请求后,内存永远不会释放。如果我一直上传文件,内存就会一直增加,直到服务器完全关闭
我们不能将文件直接从多部分表单发送到API,因为我们需要在之前发送和验证一些数据(业务需求/规则)。经过研究,我提出了这种方法,但内存泄漏问题与我有关
我错过什么了吗?垃圾收集器应该立即收集内存吗?在所有一次性对象中,我都使用“使用”语法,但它没有帮助
我也很好奇这种上传文件的方法。我应该换一种方式吗
为了澄清,API与MVC应用程序分离(每个应用程序都托管在IIS中一个单独的网站上),并且都在C#中。1。垃圾收集器是否应该立即收集内存? 垃圾收集器不会立即释放内存,因为这是一个耗时的操作。当发生垃圾回收时,所有应用程序的托管线程都将暂停。这会引入不必要的延迟。因此,垃圾收集器只是偶尔根据复杂的算法进行操作 2。在所有一次性对象中,我都使用了“使用”语法,但没有任何帮助。
using
语句处理供应有限的非托管资源
(通常与IO相关,如文件句柄、数据库和网络连接)。因此,此语句不影响垃圾收集
3。我错过了什么吗?
在使用ByteArrayContent
对原始字节数组进行包装后,似乎不需要它。包装后不清理model.File
,数组最终可能会传递到索引视图
我将替换:
using(var binaryReader = new BinaryReader(file.InputStream)) {
model.File = binaryReader.ReadBytes(file.ContentLength);
}
var fileContent = new ByteArrayContent(model.File);
与:
避免需要明确地清理model.File
4。如果我一直上传文件,内存就会一直增加,直到服务器完全关闭。
如果您的文件平均为80MB,那么它们最终将位于大型对象堆上。堆不会自动压缩,通常不会进行垃圾收集。在您的例子中,大型对象堆似乎无限期地增长(这是可能发生的)
如果您正在使用(或可以升级到).NET 4.5.1或更新版本,则可以通过以下设置强制压缩大型对象堆:
System.Runtime.GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
每次您希望在下一次完全垃圾收集时安排大型对象堆压缩时,都需要调用这一行代码
您还可以通过调用以下命令强制立即压缩:
System.Runtime.GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
System.GC.Collect();
然而,如果您需要释放大量内存,这将是一个在时间方面代价高昂的操作
System.Runtime.GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
System.Runtime.GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
System.GC.Collect();