sti*_*k81 10 .net c# wpf memory-leaks bitmapsource
我的应用程序中存在内存泄漏问题,它会加载大量图像.我对C#很陌生,并认为我的内存泄漏问题已经过去了.我无法弄清楚问题 - 也许我正在使用一些我无法正确处理的非托管模块?
为了说明我的问题,我简化了导致问题的核心,并将其转移到一个干净的项目中.请注意,这都是愚蠢的代码,不能反映它来自的原始应用程序.在测试应用程序中,我有2个按钮,触发两个事件.
按钮1 - 创建:将对象设置为datacontext.这将通过将对象设置为DataContext来加载图像并使它们保持活动状态:
var imgPath = @"C:\some_fixed_path\img.jpg";
DataContext = new SillyImageLoader(imgPath);
Run Code Online (Sandbox Code Playgroud)
按钮2 - 清理:我的理解是,如果我放开持有SillyImageLoader再次保存图像的引用,那么这将被删除.我还明确地触发垃圾收集,只是为了在删除引用后立即查看内存量.
DataContext = null;
System.GC.Collect();
Run Code Online (Sandbox Code Playgroud)
测试时我正在加载一个974KB的jpeg图像.保持30位图表示可以将我的应用程序的内存使用量从大约18MB增加到大约562MB.好.但是当我清理时,内存只下降到~292MB.如果我重复Create + CleanUp,我还剩下另外~250MB的内存.所以显然某人仍然持有一些东西.
这是SillyImageLoader代码:
namespace MemoryLeakTest
{
using System;
using System.Drawing;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media.Imaging;
public class SillyImageLoader
{
private BitmapSource[] _images;
public SillyImageLoader(string path)
{
DummyLoad(path);
}
private void DummyLoad(string path)
{
const int numberOfCopies = 30;
_images = new BitmapSource[numberOfCopies];
for (int i = 0; i < numberOfCopies; i++)
{
_images[i] = LoadImage(path);
}
}
private static BitmapSource LoadImage(string path)
{
using (var bmp = new Bitmap(path))
{
return Imaging.CreateBitmapSourceFromHBitmap(
bmp.GetHbitmap(),
IntPtr.Zero,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
有任何想法吗?问题似乎与BitmapSource有关.仅保留Bitmap没有内存泄漏.我正在使用BitmapSource将其设置为Image的Source属性.我应该这样做吗?如果是这样 - 我仍然想知道内存泄漏的答案.
谢谢.
Mar*_*ris 13
你打电话的时候
bmp.GetHbitmap()
Run Code Online (Sandbox Code Playgroud)
创建位图的副本.您需要保持对该对象的指针的引用并调用
DeleteObject(...)
Run Code Online (Sandbox Code Playgroud)
在上面.
从这里:
备注
您负责调用GDI DeleteObject方法来释放GDI位图对象使用的内存.
您可以通过使用BitmapImage而不是BitmapSource 来节省复制位图的麻烦(和开销).这允许您一步加载和创建.
您需要DeleteObject
在IntPtr
从GetHBitmap()返回的指针上调用GDI 方法.在IntPtr
从方法返回是一个指向该对象的存储器中的拷贝.必须使用以下代码手动释放:
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr hObject);
private static BitmapSource LoadImage(string path)
{
BitmapSource source;
using (var bmp = new Bitmap(path))
{
IntPtr hbmp = bmp.GetHbitmap();
source = Imaging.CreateBitmapSourceFromHBitmap(
hbmp,
IntPtr.Zero,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());
DeleteObject(hbmp);
}
return source;
}
Run Code Online (Sandbox Code Playgroud)
看来,当你调用GetHBitmap()时,你负责释放对象
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr hObject);
private void DoGetHbitmap()
{
Bitmap bm = new Bitmap("Image.jpg");
IntPtr hBitmap = bm.GetHbitmap();
DeleteObject(hBitmap);
}
Run Code Online (Sandbox Code Playgroud)
我猜测BitmapSource不负责释放这个对象.
归档时间: |
|
查看次数: |
8692 次 |
最近记录: |