gpt4 book ai didi

c# - 使用页面和 BitmapImage 的 WPF 应用程序中的内存泄漏

转载 作者:太空宇宙 更新时间:2023-11-03 13:01:33 29 4
gpt4 key购买 nike

我对 C# 和一般编程还是很陌生,但到目前为止我已经做了一些应用程序。只执行一项任务然后退出的普通应用程序已经足够简单,但是让一个系统例如每天拍摄 500 张用户照片给了我更大的挑战。

我的问题是关于 WPF 中的内存消耗。我有以下页面,加载时它会占用越来越多的内存。我尝试使用内存分析器工具并创建了一些快照来尝试解决此问题。但是,我很难理解何时/如何处理对象并确保 GC 负责其余的工作。我遇到特别麻烦的页面之一是:

第 2 页:

using EDSDKLib;
using PhotoBooth.Functions;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;

namespace PhotoBooth.Pages
{
/// <summary>
/// Interaction logic for Picture.xaml
/// </summary>
public partial class Picture : Page
{
int secondsToWait = 4;
DispatcherTimer dispatcherTimer;
Action<BitmapImage> SetImageAction;
ImageBrush bgbrush = new ImageBrush();

public Picture()
{
InitializeComponent();

// Define steps
Global.CreateSteps(Global.SelectedMenuOrder, this, ((MasterPage)System.Windows.Application.Current.MainWindow).StepsWindow);

// Create TempLocation
Directory.CreateDirectory(Settings.TempLocation);

// Handle the Canon EOS camera
Global.CameraHandler.ImageSaveDirectory = Settings.TempLocation;
SetImageAction = (BitmapImage img) => { bgbrush.ImageSource = img; };

// Configure the camera timer
dispatcherTimer = new DispatcherTimer();
dispatcherTimer.Tick += DispatcherTimer_Tick;
dispatcherTimer.Interval = new TimeSpan(0, 0, 0, 0, 800);
}

private void Page_Loaded(object sender, RoutedEventArgs e)
{
// Subscribe to camera events
if (Global.CameraHandler != null)
{
Global.CameraHandler.LiveViewUpdated += CameraHandler_LiveViewUpdated;
Global.CameraHandler.ImageSaved += CameraHandler_ImageSaved;
Global.CameraHandler.CameraSDKError += CameraHandler_CameraSDKError;
}

// Start LiveView
try
{
Console.WriteLine(Global.CameraHandler.IsLiveViewOn);
if (!Global.CameraHandler.IsLiveViewOn)
{
CameraLiveView.Background = bgbrush;
Global.CameraHandler.StartLiveView();
}
}
catch (Exception)
{
// We cannot recover from that kind of errror. Reboot the application
CameraCrashHandler();
}
}

private void CameraTrigger_Click(object sender, RoutedEventArgs e)
{
// The user has clicked the trigger, change the layout
CameraTrigger.Visibility = System.Windows.Visibility.Collapsed;
CameraCountDown.Visibility = System.Windows.Visibility.Visible;
CameraTrigger.IsEnabled = false;

// Start the countdown
secondsToWait = 4;
dispatcherTimer.Start();
Global.WriteToLog("INFO", "Camera shutter pressed... waiting for camera to take picture!");
}

private void DispatcherTimer_Tick(object sender, EventArgs e)
{
// Handles the countdown
switch (secondsToWait)
{
case 4:
CameraTimer3.Foreground = new SolidColorBrush(Colors.White);
Global.PlaySound("pack://application:,,,/Resources/Audio/camera_beep.wav");
break;
case 3:
CameraTimer2.Foreground = new SolidColorBrush(Colors.White);
Global.PlaySound("pack://application:,,,/Resources/Audio/camera_beep.wav");
break;
case 2:
CameraTimer1.Foreground = new SolidColorBrush(Colors.White);
Global.PlaySound("pack://application:,,,/Resources/Audio/camera_beep.wav");
break;
case 1:
CameraTimer0.Source = new BitmapImage(new Uri("pack://application:,,,/Resources/Images/icon_cameraWhite.png"));
Global.CameraFlashEffect(((MasterPage)System.Windows.Application.Current.MainWindow).CameraFlash);
Global.CameraHandler.TakePhoto();
break;
case 0:
CameraTimer0.Source = new BitmapImage(new Uri("pack://application:,,,/Resources/Images/icon_cameraRed.png"));
CameraTimer1.Foreground = (SolidColorBrush)(new BrushConverter().ConvertFrom("#e8234a"));
CameraTimer2.Foreground = (SolidColorBrush)(new BrushConverter().ConvertFrom("#e8234a"));
CameraTimer3.Foreground = (SolidColorBrush)(new BrushConverter().ConvertFrom("#e8234a"));

dispatcherTimer.Stop();
break;
default:
break;
}

secondsToWait--;
}

private void Page_Unloaded(object sender, RoutedEventArgs e)
{
// Stop LiveView
if (Global.CameraHandler.IsLiveViewOn)
{
CameraLiveView.Background = null;
Global.CameraHandler.StopLiveView();
}

// Unsubscribe from events
Global.CameraHandler.LiveViewUpdated -= CameraHandler_LiveViewUpdated;
Global.CameraHandler.ImageSaved -= CameraHandler_ImageSaved;
Global.CameraHandler.CameraSDKError -= CameraHandler_CameraSDKError;
}

#region CameraHandler

void CameraHandler_CameraSDKError(string error)
{
// Handle known errors
Global.WriteToLog("ERROR", "CameraSDKError: " + error);
switch (error)
{
case "0x00008D01":
// Reset cameraTrigger for taking another photo
this.Dispatcher.Invoke((Action)(() =>
{
CameraTrigger.Visibility = System.Windows.Visibility.Visible;
CameraCountDown.Visibility = System.Windows.Visibility.Collapsed;
CameraTrigger.IsEnabled = true;
}));
break;
default:
CameraCrashHandler();
break;
}
}

void CameraHandler_ImageSaved(string img)
{
// Assign image to user
Global.PersonObject.Image = img;

// We have a image, let's navigate to the next page
this.Dispatcher.Invoke((Action)(() =>
{
NavigationService.Navigate(Global.FindPageByString(Global.NavigateManager(this, Functions.Enums.Navigation.Forward)));
}));
}

void CameraHandler_LiveViewUpdated(Stream img)
{
try
{
if (Global.CameraHandler.IsLiveViewOn)
{
using (WrappingStream s = new WrappingStream(img))
{
img.Position = 0;
BitmapImage EvfImage = new BitmapImage();
EvfImage.BeginInit();
EvfImage.StreamSource = s;
EvfImage.CacheOption = BitmapCacheOption.OnLoad;
EvfImage.EndInit();
EvfImage.Freeze();
Application.Current.Dispatcher.Invoke(SetImageAction, EvfImage);
}
}
}
catch (Exception ex)
{
Global.WriteToLog("ERROR", "LiveViewUpdated failed: " + ex.Message);
}
}

static void CameraCrashHandler()
{
// Camera cannot start
Global.WriteToLog("ERROR", "Unkown CameraSDKError. Automatic reboot needed");
MessageWindow mw = new MessageWindow("CameraErrorTitle", "CameraErrorMessage");
mw.ShowDialog();

// We cannot recover from that kind of errror. Reboot the application
System.Windows.Forms.Application.Restart();
System.Windows.Application.Current.Shutdown();
}

#endregion
}
}

第 3 页:

using PhotoBooth.Functions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace PhotoBooth.Pages
{
/// <summary>
/// Interaction logic for PreviewID.xaml
/// </summary>
public partial class PreviewID : Page
{
public PreviewID()
{
InitializeComponent();

// Define steps
Global.CreateSteps(Global.SelectedMenuOrder, this, ((MasterPage)System.Windows.Application.Current.MainWindow).StepsWindow);

// Load image and data
PreviewIDText = GetIDText(Global.PersonObject, PreviewIDText);
PreviewIDCard.Source = GetIDPhoto(Global.PersonObject);
PreviewIDPhoto.Background = new ImageBrush(new BitmapImage(new Uri(Global.PersonObject.Image)));
}

private void PreviewIDRetry_Click(object sender, RoutedEventArgs e)
{
Global.WriteToLog("INFO", "User did not approve the image, retry!");
NavigationService.Navigate(Global.FindPageByString(Global.NavigateManager(this, Functions.Enums.Navigation.Backward)));
}

private void PreviewIDAccept_Click(object sender, RoutedEventArgs e)
{
Global.WriteToLog("INFO", "User approved the image");
NavigationService.Navigate(Global.FindPageByString(Global.NavigateManager(this, Functions.Enums.Navigation.Forward)));
}

public TextBlock GetIDText(Functions.Enums.Person p, TextBlock tb)
{
tb.Text = "";
tb.FontSize = 24;

if (p.Affiliation == Functions.Enums.Affiliation.Employee)
{
// Ansatt
tb.Inlines.Add(new Run(p.FirstName + " " + p.LastName + Environment.NewLine) { FontWeight = FontWeights.Bold, FontSize = 30 });
tb.Inlines.Add(p.Title + Environment.NewLine);
tb.Inlines.Add(p.Department + Environment.NewLine);
tb.Inlines.Add("Ansatt nr: " + p.EmployeeNumber + Environment.NewLine);
}
else
{
// Student
tb.Inlines.Add("Last name: ");
tb.Inlines.Add(new Run(p.LastName + Environment.NewLine) { FontWeight = FontWeights.Bold });
tb.Inlines.Add("First name: ");
tb.Inlines.Add(new Run(p.FirstName + Environment.NewLine) { FontWeight = FontWeights.Bold });
tb.Inlines.Add("Date of birth: ");
tb.Inlines.Add(new Run("dd.mm.yyyy" + Environment.NewLine) { FontWeight = FontWeights.Bold });
tb.Inlines.Add("Studentnr: ");
tb.Inlines.Add(new Run("xxxxxx" + Environment.NewLine) { FontWeight = FontWeights.Bold });
}

return tb;
}

public BitmapImage GetIDPhoto(Functions.Enums.Person p)
{
BitmapImage result;
switch (p.Affiliation)
{
case PhotoBooth.Functions.Enums.Affiliation.Student:
result = new BitmapImage(new Uri("pack://application:,,,/Resources/Images/idcard_student.png"));
break;
case PhotoBooth.Functions.Enums.Affiliation.Employee:
result = new BitmapImage(new Uri("pack://application:,,,/Resources/Images/idcard_employee.png"));
break;
default:
result = new BitmapImage(new Uri("pack://application:,,,/Resources/Images/idcard_student.png"));
break;
}

return result;
}

private void Page_Unloaded(object sender, RoutedEventArgs e)
{
PreviewIDPhoto.Background = null;
}
}
}

虽然大部分是全局的。所有其他页面上都使用了函数,它们似乎很好,因为据我所知,正是这个页面造成了我的大部分麻烦。

这是我的内存性能测试的屏幕截图。

  1. 用户从第 1 页导航到第 2 页(或其他页面),据我所知没有问题。内存使用似乎很稳定。

  2. 用户使用 LiveView 触发佳能相机(第 2 页)。内存消耗上下波动,但稳定。

  3. 用户拍摄图像并进行预览(第 3 页)、重试(返回到第 2 页)、拍摄另一张、重试等等...

    每次加载后面的代码时:

enter image description here

是位图图像导致了这个问题吗?如果该代码中没有明显的内容,我应该如何继续测试内存泄漏?

最佳答案

我认为是因为 DispatcherTimer。卸载页面时可能仅停止计时器是不够的,因为 WPF 仍会存储对您的类的引用。卸载页面时尝试注销该事件。

关于c# - 使用页面和 BitmapImage 的 WPF 应用程序中的内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32125606/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com