[英]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.