内存泄漏问题:处置或不处置托管资源?

我在计算昂贵的基于内容的图像检索(CBIR).NET应用程序中遇到奇怪的内存泄漏

概念是有一个带有线程循环的服务类,它捕获来自某些源的图像,然后将它们传递给图像标记线程以进行注释。

服务类以指定的时间间隔从存储库中查询映像标记,并将其存储在其内存缓存(字典)中,以避免频繁的数据库命中。

该项目中的类是:

class Tag { public Guid Id { get; set; } // tag id public string Name { get; set; } // tag name: eg 'sky','forest','road',... public byte[] Jpeg { get; set; } // tag jpeg image patch sample } class IRepository { public IEnumerable FindAll(); } class Service { private IDictionary Cache { get; set; } // to avoid frequent db reads // image capture background worker (ICBW) // image annotation background worker (IABW) } class Image { public byte[] Jpeg { get; set; } public IEnumerable Tags { get; set; } } 

ICBW工作人员从一些图像源捕获jpeg图像并将其传递给IABW工作者进行注释。 IABW工作者首先尝试更新缓存,如果时间已到,然后通过一些算法创建Image对象并将标签附加到它然后将其存储到注释存储库来注释图像。

IABW worker中的服务缓存更新片段是:

 IEnumerable tags = repository.FindAll(); Cache.Clear(); tags.ForEach(t => Cache.Add(t.Id, t)); 

IABW每秒被调用很多次,并且处理器非常广泛。

运行数天后,我发现任务管理器内存增加了。 使用Perfmon在所有堆中观察进程/专用字节和.NET内存/字节,我发现它们都随着时间的推移而增加。

试验应用程序,我发现Cache更新是个问题。 如果没有更新,则mem增加没有问题。 但是如果缓存更新在1-5分钟内频繁发生,那么应用程序会快速获得内存。

内存泄漏的原因可能是什么? 经常创建图像对象,其中包含对Cache中Tag对象的引用。 我假设在创建Cache字典时,这些引用在某种程度上不会在将来被垃圾收集。

是否需要显式地使托管的byte []对象为空以避免内存泄漏,例如通过将Tag,Image作为IDisposable

编辑:2001年8月4日,添加了错误的代码片段导致快速内存泄漏。

 static void Main(string[] args) { while (!Console.KeyAvailable) { IEnumerable data = CreateEnumeration(100); PinEntries(data); Thread.Sleep(900); Console.Write(String.Format("gc mem: {0}\r", GC.GetTotalMemory(true))); } } static IEnumerable CreateEnumeration(int size) { Random random = new Random(); IList data = new List(); for (int i = 0; i < size; i++) { byte[] vector = new byte[12345]; random.NextBytes(vector); data.Add(vector); } return data; } static void PinEntries(IEnumerable data) { var handles = data.Select(d => GCHandle.Alloc(d, GCHandleType.Pinned)); var ptrs = handles.Select(h => h.AddrOfPinnedObject()); IntPtr[] dataPtrs = ptrs.ToArray(); Thread.Sleep(100); // unmanaged function call taking byte** data handles.ToList().ForEach(h => h.Free()); } 

不,如果它只是你所显示的内存,你不需要将任何东西设置为null或处理任何东西。

我建议你抓住一个好的剖析器来找出漏洞的位置。 你有什么非内存相关的,你可能没有处理,例如加载GDI +图像来获取字节?