我正在使用 .NET 8 的官方版本来开发 Blazor MAUI 混合应用程序。
我有一个功能,用户可以选择图像并将其显示给用户。我正在使用 Base64,但我注意到内存泄漏。这是我的代码:
@page "/memory_leak"
@using System.Diagnostics
<MudStack Class="ma-4" AlignItems="AlignItems.Center">
<MudPaper Class="pa-3" Elevation="3">
@if (_imageBase64 is null)
{
<MudAlert Severity="Severity.Normal">Choose an Image</MudAlert>
}
else
{
<MudImage Height="400" Alt="pic" Class="rounded-lg"
Src="@string.Concat("data:image/png;base64,", _imageBase64)"
/>
}
</MudPaper>
<MudFileUpload T="IBrowserFile" FilesChanged="UploadFiles" Class="pa-3">
<ButtonTemplate>
<MudFab
Size="Size.Small"
HtmlTag="label"
Color="Color.Secondary"
Icon="@Icons.Material.Filled.Image"
Label="Load picture"
for="@context" />
</ButtonTemplate>
</MudFileUpload>
<MudPaper Class="pa-3">Item 3</MudPaper>
</MudStack>
@code
{
private string? _imageBase64;
private async Task UploadFiles(IBrowserFile file)
{
Debug.WriteLine($"size:{file.Size}");
await using var openReadStream = file.OpenReadStream(file.Size);
byte[] buffer = new byte[file.Size];
var readAsync = await openReadStream.ReadAsync(buffer);
_imageBase64 = Convert.ToBase64String(buffer, 0, readAsync);
}
}
每当我上传图像时,内存都会增加,并且垃圾收集器(GC)不会回收多余的内存。这一直持续到页面最终崩溃
我正在尝试消除其他可能的原因,我发现当我注释掉
Src="@string.Concat("data:image/png;base64,", _imageBase64)"
时,内存泄漏不再发生。这表明图像显示导致了内存泄漏。
为了排除与MudBlazor相关的问题,我直接使用HTML标签,但仍然出现内存泄漏:
@* <MudImage Height="400" Alt="pic" Class="rounded-lg"
Src="@string.Concat("data:image/png;base64,", _imageBase64)"
/> *@
<img src="@string.Concat("data:image/png;base64,", _imageBase64)" class="rounded-lg" height="400px"/>
最后,我通过使用 JavaScript 对象 URL 解决了这个问题。
但是,我仍然很好奇这个内存泄漏是如何发生的。我想知道我的使用是否存在问题,或者 Blazor 是否存在潜在的错误。我搜索了类似的问题,但找不到其他人遇到同样的问题。
这可以参考文档:ASP.NET Core Blazor 文件上传。
在以下示例中,
browserFile
代表上传的文件并实现IBrowserFile
。本文后面的文件上传组件中显示了 IBrowserFile
的工作实现。
❌不支持:不建议使用以下方法,因为文件的 Stream 内容被读入内存中的字符串(读取器):
var reader =
await new StreamReader(browserFile.OpenReadStream()).ReadToEndAsync();
❌不支持:不建议将以下方法用于 Microsoft Azure Blob 存储,因为在调用 UploadBlobAsync 之前,文件的 Stream 内容会复制到内存中的 MemoryStream (memoryStream) 中:
var memoryStream = new MemoryStream();
browserFile.OpenReadStream().CopyToAsync(memoryStream);
await blobContainerClient.UploadBlobAsync(
trustedFileName, memoryStream));
✔️支持:建议使用以下方法,因为文件的 Stream 是直接提供给消费者的,即在提供的路径创建文件的 FileStream:
await using FileStream fs = new(path, FileMode.Create);
await browserFile.OpenReadStream().CopyToAsync(fs);
✔️支持:对于 Microsoft Azure Blob 存储,建议使用以下方法,因为文件的 Stream 直接提供给 UploadBlobAsync:
await blobContainerClient.UploadBlobAsync(
trustedFileName, browserFile.OpenReadStream());