我使用此功能创建了一个图像:
private BitmapImage LoadImage(byte[] imageData)
{
if (imageData == null || imageData.Length == 0) return null;
var image = new BitmapImage();
using (var mem = new MemoryStream(imageData))
{
mem.Position = 0;
image.BeginInit();
image.CreateOptions = BitmapCreateOptions.PreservePixelFormat;
image.CacheOption = BitmapCacheOption.OnLoad;
image.UriSource = null;
image.StreamSource = mem;
image.EndInit();
}
image.Freeze();
return image;
}
当我试图处理它时:
myImage.StreamSource.Close();
myImage.StreamSource.Dispose();
// Throws an exception since its frozen to read only
//myImage.StreamSource = null;
GC.Collect();
它不是由垃圾收集器收集的。可能因为我无法将其设置为null
。
如何处理此BitmapImage
以便它在内存中的存活时间不长?
答案 0 :(得分:0)
您已经处置了StreamSource
,因为您在using语句中创建了MemoryStream
,该语句在离开代码块时处理。 BitmapImage
本身仅供管理,不需要处理。
你确定它没有被垃圾收集器清理干净吗?我有一个项目用BitmapImage
制作了很多BitmapCacheOption.OnLoad
个,我从来没有看到过它的内存泄漏。
(更新)在WPF中测试:(Update2)需要添加另一轮垃圾收集。出于某种原因,你必须调用它两次才能释放数组。
private async void Button_Click(object sender, RoutedEventArgs e)
{
WeakReference test = this.TestThing();
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
Debug.WriteLine(test.IsAlive); // Returns false
}
private WeakReference TestThing()
{
byte[] imageData = File.ReadAllBytes(@"D:\docs\SpaceXLaunch_Shortt_3528.jpg");
var image = new BitmapImage();
using (var mem = new MemoryStream(imageData))
{
image.BeginInit();
image.CreateOptions = BitmapCreateOptions.PreservePixelFormat;
image.CacheOption = BitmapCacheOption.OnLoad;
image.UriSource = null;
image.StreamSource = mem;
image.EndInit();
}
image.Freeze();
return new WeakReference(image);
}
答案 1 :(得分:0)
我们可以使用以下代码调查此问题:
public static void Main()
{
var readAllBytes = File.ReadAllBytes(@"SomeBitmap.bmp");
var wr = new WeakReference(readAllBytes);
var result = LoadImage(readAllBytes);
readAllBytes = null;
//result.StreamSource = null;
result = null;
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine($"IsAlive: {wr.IsAlive}");
Console.ReadLine();
}
private static BitmapImage LoadImage(byte[] imageData)
{
if (imageData == null || imageData.Length == 0) return null;
var image = new BitmapImage();
using (var mem = new MemoryStream(imageData))
{
mem.Position = 0;
image.BeginInit();
image.CreateOptions = BitmapCreateOptions.PreservePixelFormat;
image.CacheOption = BitmapCacheOption.OnLoad;
image.UriSource = null;
image.StreamSource = mem;
image.EndInit();
}
image.Freeze();
return image;
}
我尝试了很多缓存设置,我找不到释放字节数组的方法,它看起来像是WPF中的一个错误。
如您所见,在2个GC集合之后,字节数组被释放。
编辑1:通过删除冻结简化BitmapImage
并且Init
方法确实释放字节数组:
private static BitmapImage LoadImage(byte[] imageData)
{
if (imageData == null || imageData.Length == 0) return null;
var image = new BitmapImage();
using (var mem = new MemoryStream(imageData))
{
mem.Position = 0;
image.CreateOptions = BitmapCreateOptions.PreservePixelFormat;
image.UriSource = null;
image.StreamSource = mem;
}
return image;
}
编辑2:我正如其他人所说,字节数组在2轮垃圾收集后被释放,我已经更新了顶级示例。我发现这非常有用,它表明框架不是黑盒子。
答案 2 :(得分:0)
就我而言,我需要在存储为服务器字节数组的一堆大型平面图之间进行切换。一旦将所有这些都加载到内存中,并且在它们之间进行了一些切换之后,我坐在3GB内存上,开始遇到所有加载的问题。图像本身的范围从600KB到几兆字节。绘制它们时,它们会占用更多空间。
我发现了一个包装流实现 此处(http://faithlife.codes/blog/2009/05/wrappingstream_implementation/),来自Bradley Grainger。
这使我的内存使用率相当低;大多数时候少于2GB。
WrapperStream MasterStream{get;set;}
private void ChangeImage()
{
SelectedImage = null;
GC.Collect();
var stream = new MemoryStream(ImageSource);
using (MasterStream = new WrappingStream(stream))
{
var bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.StreamSource = MasterStream;
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.EndInit();
bitmap.Freeze();
SelectedImage = bitmap;
}
GC.Collect();
}