我在计算昂贵的基于内容的图像检索(CBIR).NET应用程序中遇到奇怪的内存泄漏
概念是有一个带有线程循环的服务类,它捕获来自某个源的图像,然后将它们传递给图像标记线程以进行注释。
服务类以指定的时间间隔从存储库中查询图像标记,并将其存储在其内存缓存(字典)中,以避免频繁的数据库命中。
项目中的课程是:
class Tag
{
public Guid Id { get; set; } // tag id
public string Name { get; set; } // tag name: e.g. 'sky','forest','road',...
public byte[] Jpeg { get; set; } // tag jpeg image patch sample
}
class IRepository
{
public IEnumerable<Tag> FindAll();
}
class Service
{
private IDictionary<Guid, Tag> 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<Tag> Tags { get; set; }
}
ICBW工作人员从某些图像源捕获jpeg图像,并将其传递给IABW工作人员进行注释。 IABW工作者首先尝试更新Cache,如果时间已到,然后通过一些算法创建Image对象并将标签附加到它然后将其存储到注释存储库来注释图像。
IABW worker中的服务缓存更新片段是:
IEnumerable<Tag> tags = repository.FindAll();
Cache.Clear();
tags.ForEach(t => Cache.Add(t.Id, t));
每秒多次调用IABW并且处理器非常广泛。
运行数天后,我发现任务管理器内存增加了。使用Perfmon在所有堆中观察进程/专用字节和.NET内存/字节,我发现它们都在不断增加。
试验应用程序我发现缓存更新是个问题。如果没有更新,则mem增加没有问题。但是如果缓存更新在1-5分钟内频繁发生一次,则应用程序会快速获取内存。
内存泄漏可能是什么原因?经常创建图像对象,其中包含对Cache中Tag对象的引用。我假设在创建缓存字典时,这些引用将来不会被垃圾收集。
是否需要显式地使托管的byte []对象为空以避免内存泄漏,例如通过实施标记,图像为IDisposable
?
编辑:2001年8月4日,添加了错误的代码片段,导致快速内存泄漏。
static void Main(string[] args)
{
while (!Console.KeyAvailable)
{
IEnumerable<byte[]> data = CreateEnumeration(100);
PinEntries(data);
Thread.Sleep(900);
Console.Write(String.Format("gc mem: {0}\r", GC.GetTotalMemory(true)));
}
}
static IEnumerable<byte[]> CreateEnumeration(int size)
{
Random random = new Random();
IList<byte[]> data = new List<byte[]>();
for (int i = 0; i < size; i++)
{
byte[] vector = new byte[12345];
random.NextBytes(vector);
data.Add(vector);
}
return data;
}
static void PinEntries(IEnumerable<byte[]> 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());
}
答案 0 :(得分:1)
不,如果它只是你所显示的内存,你不需要将任何东西设置为null或处理任何东西。
我建议你抓住一个好的剖析器来找出漏洞的位置。你有什么非记忆相关的,你可能没有处理,例如加载GDI +图像以获取字节?