如何使用位图图像设置图像的源后释放内存
本文关键字:图像 释放 内存 设置 何使用 位图 | 更新日期: 2023-09-27 18:31:01
我在WPF中有一个用户控件,它包含一个图像,并且它与ImgSource绑定了Source:
public ImageWithWatingCtl()
{
this.DataContext = this;
InitializeComponent();
story = (base.Resources["waiting"] as Storyboard);
StartLoading();
}
private ImageSource imgSource;
public ImageSource ImgSource
{
get { return imgSource; }
set
{
if (imgSource != null)
{
imgSource = null;
}
imgSource = value;
this.Dispatcher.BeginInvoke(new Action(() => { StopLoading(); }));
OnPropertyChanged("ImgSource");
}
}
public string Source
{
get { return (string)GetValue(SourceProperty); }
set { SetValue(SourceProperty, value); }
}
public static readonly DependencyProperty SourceProperty =
DependencyProperty.Register("Source", typeof(string), typeof(ImageWithWatingCtl), new FrameworkPropertyMetadata(new PropertyChangedCallback(CallBack)));
private static void CallBack(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ImageWithWatingCtl imgCtl = d as ImageWithWatingCtl;
imgCtl.path = e.NewValue != null ? e.NewValue.ToString() : "";
imgCtl.GetImage();
}
private void GetImage()
{
if (!string.IsNullOrEmpty(path))
{
service.OnComplate += service_OnComplate;
service.EnQueue(path);
}
}
void service_OnComplate(string url, BitmapImage bitmap)
{
if (url == path)
{
if (bitmap != null)
{
if (ImgSource == null)
ImgSource = bitmap;
}
}
}
private void StartLoading()
{
this.story.Begin();
imageLoading.Visibility = Visibility.Visible;
}
private void StopLoading()
{
this.story.Stop();
imageLoading.Visibility = Visibility.Collapsed;
}
此控件获取一个 url 并将其发送到 GetImageService:
public delegate void ComplateDelegate(string url, BitmapImage bitmap);
public event ComplateDelegate OnComplate;
private List<string> LstImageInfo { get; set; }
object lstlock = new object();
private static GetImageService instance = null;
private readonly static object instance_lock = new object();
public static GetImageService GetInstance()
{
if (instance == null)
{
lock (instance_lock)
{
if (instance == null)
{
instance = new GetImageService();
}
}
}
return instance;
}
private GetImageService()
{
LstImageInfo = new List<string>();
Thread getTread = new Thread(new ThreadStart(GetImage));
getTread.IsBackground = true;
getTread.Start();
}
public void EnQueue(string info)
{
lock (lstlock)
{
if (!LstImageInfo.Contains(info))
LstImageInfo.Add(info);
}
}
private void GetImage()
{
while (true)
{
lock (lstlock)
{
if (LstImageInfo.Count > 0)
{
Console.WriteLine(LstImageInfo.Count);
BitmapImage bitmap = null;
var info = LstImageInfo[0];
if (info.StartsWith("http:"))
{
bitmap = ShareClass.GetBitemapUrl(info);
}
else
{
bitmap = ShareClass.GetBitmapImage(info);
}
if (bitmap.CanFreeze)
bitmap.Freeze();
if (OnComplate != null)
OnComplate(info, bitmap);
LstImageInfo.RemoveAt(0);
}
}
Thread.Sleep(100);
}
}
用于获取图像的共享类:
public static BitmapImage GetBitmapImage(string path, int imageWidth = 0)
{
BitmapImage bitmap;
if (!File.Exists(path))
{
path = Path.Combine(GetAssemblyPath(), path);
}
if (File.Exists(path))
{
using (MemoryStream ms = new MemoryStream(File.ReadAllBytes(path)))
{
bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.CacheOption = BitmapCacheOption.OnLoad;
if (imageWidth > 0)
{
using (System.Drawing.Image drawingImage = System.Drawing.Image.FromStream(ms))
{
int old_w = drawingImage.Width;
int old_h = drawingImage.Height;
int imageHeight = (int)(old_h * (imageWidth * 1.0 / old_w));
using (System.Drawing.Image thumImage = drawingImage.GetThumbnailImage(imageWidth, imageHeight, () => { return true; }, IntPtr.Zero))
{
MemoryStream ms_thum = new MemoryStream();
thumImage.Save(ms_thum, System.Drawing.Imaging.ImageFormat.Png);
bitmap.StreamSource = ms_thum;
}
}
}
else
{
bitmap.StreamSource = ms;
}
bitmap.EndInit();
bitmap.Freeze();
}
return bitmap;
}
else
return null;
}
public static BitmapImage GetBitemapUrl(string url)
{
try
{
if (string.IsNullOrEmpty(url))
{
return null;
}
else
{
BitmapImage bitmap = new BitmapImage();
WebClient wc = new WebClient();
using (var ms = new MemoryStream(wc.DownloadData(url)))
{
bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.StreamSource = ms;
bitmap.EndInit();
if (bitmap.CanFreeze)
bitmap.Freeze();
}
return bitmap;
}
}
catch (Exception ex)
{
return null;
}
}
我已经尝试了很多方法,设置ImgSource =null
,使用GC,但没有用,那么如何释放内存还是有另一种方法可以实现我的需求?
顺便说一下,实际上GetImageService中的图片都是20~30kb,但是如果我设置ImgSource =位图,我看到内存增加超过10mb。
首先,您应该确保删除使用图像源的UI控件。气相色谱。如果 GC,收集应该工作得很好。收集无法释放内存,至少应该有一个对图像源的引用。
WPF UI 就像一棵树,在你的情况下。
UserControl -> BitmapImage -> ImageSource
UserControl 和 BitmapImage 都有 Childen、VisualChildren 和 LogicChildren,它们都可能引用您的 ImageSource。
关于这个主题有很多SO线程,这个问题的一些解决方案是
1. 冻结位图图像
原因:[从链接复制]
触发此泄漏的原因是,在后台 WPF 在静态位图图像和图像之间保持强引用。
修复/解决方法是冻结位图图像。
BitmapImage bitmap = ShareClass.GetBitemapUrl(info);
bitmap.Freeze();
OnComplate(info, bitmap);
2. 从流而不是 URI 加载图像。
您可以验证其中是否有任何可以解决内存问题。