内存泄漏问题:处置还是不处置管理资源?

我在运算昂贵的基于内容的图像检索(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工作者中的服务缓存更新片段是:

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

IABW每秒被多次调用,并且处理器非常漂亮。

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

试验应用程序,我发现缓存更新是个问题。 如果没有更新,mem增加没有问题。 但是,如果缓存更新在1-5分钟内一次就很频繁,那么应用程序就会非常快速地获取内存。

那个mem泄漏的原因可能是什么? 图像对象的创建经常包含对Cache中的标签对象的引用。 我认为,当创建缓存字典时,这些引用在某种程度上不会在将来被垃圾收集。

它是否需要明确地为null来管理byte []对象以避免内存泄漏,例如通过将Tag,Image作为IDisposable来实现?

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

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());
}

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

我建议你抓住一个好的分析器来确定泄漏的位置。 你有没有与内存无关的东西,你可能无法处理,例如加载GDI +图像来获取字节?

链接地址: http://www.djcxy.com/p/54523.html

上一篇: Memory leak problems: dispose or not to dispose managed resources?

下一篇: Any sense to set obj = null(Nothing) in Dispose()?