Я построил ASP.NET MVC API, размещенный на IIS в Windows 10 Pro (ВМ на Azure - 4 ГБ ОЗУ, 2CPU). Внутри я вызываю .exe ( wkhtmltopdf ), который хочу преобразовать HTML-страницу в изображение и сохранить ее локально. Все работает отлично, за исключением того, что я заметил, что после некоторых вызовов API ОЗУ сходит с ума, и, исследуя процесс с помощью диспетчера задач, я увидел процесс, называемый IIS Worker Process, который добавляет больше ОЗУ при каждом вызове API. Конечно, я завернул использование экземпляра System.Diagnostics.Process внутри оператора using для удаления, потому что реализован IDisposable, но он по-прежнему потребляет все больше и больше оперативной памяти, и через некоторое время сервер становится неактивным и не отвечает (у него всего 4 ГБ ОЗУ). в конце концов). Я заметил, что через некоторое количество минут (возможно, 10-15-20) этот рабочий процесс IIS успокаивается с точки зрения использования оперативной памяти ... Вот мой код, довольно простой:
- Получает URL в кодировке base64
- Расшифровывает это
- Использует wkhtmltoimage.exe для преобразования его в изображение
- Сохраняет локально
- Считывает байтовый массив
- Создает BLOB-объект в Azure с изображением
Возвращает JSON с URL
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;
}
Вот ресурсы, которые я читаю, так или иначе связанные с этой проблемой IMO, но они мало помогают:
Исследование дампов памяти ASP.Net для идиотов (таких как я)
Приложение ASP.NET ест память. Объекты Application / Session причина?
Рабочий процесс IIS, использующий много памяти?
Запуск метода dispose при перезапуске приложения IIS asp.net
IIS: время ожидания простоя против перезапуска
UPDATE:
if (System.IO.File.Exists(path: LocalImageFilePath))
{
string BlobName = Guid.NewGuid().ToString(format: "n");
string ImageURL = string.Empty;
using(FileStream fileStream = new FileStream(LocalImageFilePath, FileMode.Open)
{
ImageURL = await CreateBlob(blobName: $"{BlobName}.png", dataStream: fileStream);
}
System.IO.File.Delete(path: LocalImageFilePath);
oJSON = new { url = ImageURL };
}