C# 在IIS上执行一个进程会使RAM上升得非常快
我在Windows10Pro上构建了一个ASP.NETMVCAPI托管在IIS上(Azure-4GB RAM上的虚拟机,2CPU)。在其中,我调用了一个.exe(),希望将HTML页面转换为图像并保存在本地。一切正常,只是我注意到在一些API调用之后,RAM变得疯狂,在使用Task Manager调查流程时,我看到了一个名为IIS Worker process的流程,该流程在每次调用API时都会添加更多RAM。当然,我将我的System.Diagnostics.Process实例使用情况包装在一个using语句中以进行处理,因为实现了IDisposable,但它仍然会消耗越来越多的RAM,过了一段时间服务器就会变得迟钝和无响应(毕竟它只有4GB的RAM)。我注意到在几分钟后(可能是10-15-20分钟),这个IIS工作进程在RAM使用方面平静下来。。。这是我的代码,非常简单:C# 在IIS上执行一个进程会使RAM上升得非常快,c#,.net,asp.net-mvc,iis,memory-management,C#,.net,Asp.net Mvc,Iis,Memory Management,我在Windows10Pro上构建了一个ASP.NETMVCAPI托管在IIS上(Azure-4GB RAM上的虚拟机,2CPU)。在其中,我调用了一个.exe(),希望将HTML页面转换为图像并保存在本地。一切正常,只是我注意到在一些API调用之后,RAM变得疯狂,在使用Task Manager调查流程时,我看到了一个名为IIS Worker process的流程,该流程在每次调用API时都会添加更多RAM。当然,我将我的System.Diagnostics.Process实例使用情况包装在一
public async Task<ActionResult> Index(string url)
{
object oJSON = new { url = string.Empty };
if (!string.IsNullOrEmpty(value: url))
{
try
{
byte[] EncodedData = Convert.FromBase64String(s: url);
string DecodedURL = Encoding.UTF8.GetString(bytes: EncodedData);
using (Process proc = new Process())
{
proc.StartInfo.FileName = wkhtmltopdfExecutablePath;
proc.StartInfo.Arguments = $"--encoding utf-8 \"{DecodedURL}\" {LocalImageFilePath}";
proc.Start();
proc.WaitForExit();
oJSON = new { procStatusCode = proc.ExitCode };
}
if (System.IO.File.Exists(path: LocalImageFilePath))
{
byte[] pngBytes = System.IO.File.ReadAllBytes(path: LocalImageFilePath);
System.IO.File.Delete(path: LocalImageFilePath);
string ImageURL = await CreateBlob(blobName: $"{BlobName}.png", data: pngBytes);
oJSON = new { url = ImageURL };
}
}
catch (Exception ex)
{
Debug.WriteLine(value: ex);
}
}
return Json(data: oJSON, behavior: JsonRequestBehavior.AllowGet);
}
private async Task<string> CreateBlob(string blobName, byte[] data)
{
string ConnectionString = "DefaultEndpointsProtocol=https;AccountName=" + AzureStorrageAccountName + ";AccountKey=" + AzureStorageAccessKey + ";EndpointSuffix=core.windows.net";
CloudStorageAccount cloudStorageAccount = CloudStorageAccount.Parse(connectionString: ConnectionString);
CloudBlobClient cloudBlobClient = cloudStorageAccount.CreateCloudBlobClient();
CloudBlobContainer cloudBlobContainer = cloudBlobClient.GetContainerReference(containerName: AzureBlobContainer);
await cloudBlobContainer.CreateIfNotExistsAsync();
BlobContainerPermissions blobContainerPermissions = await cloudBlobContainer.GetPermissionsAsync();
blobContainerPermissions.PublicAccess = BlobContainerPublicAccessType.Container;
await cloudBlobContainer.SetPermissionsAsync(permissions: blobContainerPermissions);
CloudBlockBlob cloudBlockBlob = cloudBlobContainer.GetBlockBlobReference(blobName: blobName);
cloudBlockBlob.Properties.ContentType = "image/png";
using (Stream stream = new MemoryStream(buffer: data))
{
await cloudBlockBlob.UploadFromStreamAsync(source: stream);
}
return cloudBlockBlob.Uri.AbsoluteUri;
}
造成您痛苦的最可能原因是分配大字节数组:
byte[] pngBytes = System.IO.File.ReadAllBytes(path: LocalImageFilePath);
要尝试并鼓励GC更频繁地收集大型对象堆,最简单的更改是在方法末尾将GCSettings.LargeObjectHeapCompactionMode
设置为CompactOnce
。这可能会有帮助
但是,更好的办法是完全不需要使用大型阵列。为此,请更改:
private async Task<string> CreateBlob(string blobName, byte[] data)
在调用者中,您需要停止使用
ReadAllBytes
,而是使用FileStream
来读取文件。唯一会导致内存使用量增加的是CreateBlob()
,它未显示。您需要分析您的代码和内存使用情况,这不是我们可以轻松做到的。启动进程不会导致启动进程的内存增加,因此问题的一部分是转移注意力。我使用CreatBlob方法更新了问题这也可能是个问题。(如果文件较大,则更应如此)byte[]pngBytes=System.IO.file.ReadAllBytes(路径:LocalImageFilePath)代码>如果这种情况偶尔发生,进程可能会收到越来越多的内存,即使它可能没有被使用。正如其他人所说:评测你的应用程序。如果你使用FileStream
并将其传递给UploadFromStreamAsync
,性能会提高吗?注意,这将要求更改<代码>字节[]/Case>参数<代码> CreateBlob <代码>作为流,并停止使用<代码> RealAlpByth。您可以考虑卸载所有的工作,无论如何,IMO并不真正适用于请求/响应周期。您应该能够在不等待进程运行的情况下知道图像url,这样我就可以在队列中放置一条消息,并让您的进程在Azure函数或类似函数中运行。
private async Task<string> CreateBlob(string blobName, byte[] data)
private async Task<string> CreateBlob(string blobName, FileStream data)
await cloudBlockBlob.UploadFromStreamAsync(source: data);