Windows
Windows copied to clipboard
Memory Management with `ImageCropper` Control
Describe the bug
When using the ImageCropper
control in the Windows Community Toolkit Gallery, I have observed the following memory-related issues:
-
Memory Consumption: When selecting a high-resolution image (dimensions: 8000 x 8000), the memory usage increases significantly. This is expected, but a concern arises when selecting additional images or re-selecting the same image. Each new image selection causes a cumulative increase in memory usage, indicating that the previous images are not being properly disposed of.
-
Memory Usage Table:
-
After 1st image selection:
-
After 2nd image selection:
-
After 3rd image selection:
-
After 4th image selection:
-
-
Behavior: The issue escalates when attempting to find a way to dispose of objects in a WinUI 3 app. After selecting high-resolution images multiple times (with memory usage exceeding 1000 MB), the application stops running unexpectedly without any error or exception. I have not been able to identify a method to release the memory effectively after selecting a new image.
<?xml version="1.0" encoding="utf-8"?>
<Window
x:Class="MyApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MyApp"
xmlns:controls="using:CommunityToolkit.WinUI.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
<Grid RowSpacing="24">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<controls:ImageCropper x:Name="imageCropper"
Width="520"
Height="520"
AspectRatio="0"
CropShape="Rectangular"
ThumbPlacement="All" />
<StackPanel Grid.Row="1"
HorizontalAlignment="Center"
Orientation="Horizontal"
Spacing="8">
<Button Click="PickButton_Click"
Content="Pick image"
Style="{StaticResource AccentButtonStyle}" />
<Button Click="SaveButton_Click"
Content="Save"
Style="{StaticResource AccentButtonStyle}" />
<Button Click="ResetButton_Click"
Content="Reset"
Style="{StaticResource AccentButtonStyle}" />
</StackPanel>
</Grid>
</StackPanel>
</Window>
using CommunityToolkit.WinUI.Controls;
using Microsoft.UI.Xaml;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Windows.Storage.Pickers;
using Windows.Storage;
namespace MyApp
{
public sealed partial class MainWindow : Window
{
public MainWindow()
{
this.InitializeComponent();
}
private async Task PickImage()
{
var openPicker = new FileOpenPicker();
var window = this;
var hWnd = WinRT.Interop.WindowNative.GetWindowHandle(window);
WinRT.Interop.InitializeWithWindow.Initialize(openPicker, hWnd);
openPicker.ViewMode = PickerViewMode.Thumbnail;
openPicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
openPicker.FileTypeFilter.Add(".jpg");
openPicker.FileTypeFilter.Add(".jpeg");
openPicker.FileTypeFilter.Add(".png");
var file = await openPicker.PickSingleFileAsync();
if (file != null && imageCropper != null)
{
await imageCropper.LoadImageFromFile(file);
}
}
private async Task SaveCroppedImage()
{
var savePicker = new FileSavePicker
{
SuggestedStartLocation = PickerLocationId.PicturesLibrary,
SuggestedFileName = "Cropped_Image",
FileTypeChoices =
{
{ "PNG Picture", new List<string> { ".png" } },
{ "JPEG Picture", new List<string> { ".jpg" } }
}
};
var imageFile = await savePicker.PickSaveFileAsync();
if (imageFile != null)
{
BitmapFileFormat bitmapFileFormat;
switch (imageFile.FileType.ToLower())
{
case ".png":
bitmapFileFormat = BitmapFileFormat.Png;
break;
case ".jpg":
bitmapFileFormat = BitmapFileFormat.Jpeg;
break;
default:
bitmapFileFormat = BitmapFileFormat.Png;
break;
}
using (var fileStream = await imageFile.OpenAsync(FileAccessMode.ReadWrite, StorageOpenOptions.None))
{
await imageCropper.SaveAsync(fileStream, bitmapFileFormat);
}
}
}
private async void PickButton_Click(object sender, RoutedEventArgs e)
{
await PickImage();
}
private async void SaveButton_Click(object sender, RoutedEventArgs e)
{
await SaveCroppedImage();
}
private void ResetButton_Click(object sender, RoutedEventArgs e)
{
imageCropper.Reset();
}
}
}
Steps to reproduce
I. Steps to Reproduce the Memory Management Issue in WCT Gallery:
-
Run the Application:
- Launch your application to display the
MainWindow
with theImageCropper
control and the "Pick image" button.
- Launch your application to display the
-
Select a High-Resolution Image:
- Click the "Pick image" button to open the file picker.
- Choose a high-resolution image (e.g., 8000 x 8000 pixels) from your file system (this is the image I used).
-
Observe Memory Usage:
- Use Task Manager or a memory profiling tool to monitor the application's memory usage.
-
Re-select the Same High-Resolution Image:
- Click the "Pick image" button again and select the same high-resolution image you picked earlier.
- Observe the increase in memory usage.
-
Repeat the Image Selection:
- Continue clicking the "Pick image" button and re-selecting the same high-resolution image multiple times.
- Track the cumulative increase in memory usage with each image selection.
II. Steps to Reproduce the Memory Management Issue in WinUI3:
-
Setup the Application:
- Use the provided XAML and C# code to set up your WinUI 3 project.
-
Run the Application:
- Launch the application to display
MainWindow
with theImageCropper
control and the "Pick image" button.
- Launch the application to display
-
Select a High-Resolution Image:
- Click the "Pick image" button.
- Choose a high-resolution image (e.g., 8000 x 8000 pixels) from your file system.
-
Observe Memory Usage:
- Monitor the application’s memory usage using Task Manager or a similar profiling tool.
-
Re-select the Same Image:
- Click the "Pick image" button again and select the same high-resolution image you picked earlier.
- Observe the increase in memory usage.
-
Repeat the Process:
- Continue clicking the "Pick image" button and re-selecting the same high-resolution image multiple times.
- Monitor the cumulative increase in memory usage with each selection.
-
Check Application Behavior:
- Continue the process until you notice a significant increase in memory usage or if the application stops running without errors (e.g., after memory usage exceeds 1000 MB).
Expected behavior
-
Memory usage should not increase cumulatively with each selection of the same image. The previously selected image should be properly disposed of to prevent memory leaks.
-
Memory usage increases cumulatively with each image selection, suggesting that the previous image is not being disposed of correctly and remains in memory.
Screenshots
No response
Code Platform
- [ ] UWP
- [x] WinAppSDK / WinUI 3
- [ ] Web Assembly (WASM)
- [ ] Android
- [ ] iOS
- [ ] MacOS
- [ ] Linux / GTK
Windows Build Number
- [ ] Windows 10 1809 (Build 17763)
- [ ] Windows 10 1903 (Build 18362)
- [ ] Windows 10 1909 (Build 18363)
- [ ] Windows 10 2004 (Build 19041)
- [ ] Windows 10 20H2 (Build 19042)
- [ ] Windows 10 21H1 (Build 19043)
- [ ] Windows 10 21H2 (Build 19044)
- [ ] Windows 10 22H2 (Build 19045)
- [ ] Windows 11 21H2 (Build 22000)
- [ ] Other (specify)
Other Windows Build number
No response
App minimum and target SDK version
- [ ] Windows 10, version 1809 (Build 17763)
- [ ] Windows 10, version 1903 (Build 18362)
- [ ] Windows 10, version 1909 (Build 18363)
- [ ] Windows 10, version 2004 (Build 19041)
- [ ] Windows 10, version 2104 (Build 20348)
- [ ] Windows 11, version 22H2 (Build 22000)
- [ ] Other (specify)
Other SDK version
No response
Visual Studio Version
No response
Visual Studio Build Number
No response
Device form factor
No response
Additional context
No response
Help us help you
Yes, but only if others can assist.