内存泄漏问题:处置还是不处置托管资源? [英] Memory leak problems: dispose or not to dispose managed resources?

查看:119
本文介绍了内存泄漏问题:处置还是不处置托管资源?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I experience strange memory leak in computation expensive content-based image retrieval (CBIR) .NET application

概念是,存在带有线程循环的服务类,该服务类从某些来源捕获图像,然后将其传递给图像标记线程进行注释.

The concept is that there is service class with thread loop which captures images from some source and then passes them to image tagging thread for annotation.

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

Image tags are queried from repository by the service class at specified time intervals and stored in its in-memory cache (Dictionary) to avoid frequent db hits.

项目中的类为:

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,然后通过某种算法创建图像对象并将其附加标签,然后将其存储到注释存储库中,从而对该图像进行注释.

ICBW worker captures jpeg image from some image source and passes it to IABW worker for annotation. IABW worker first tries to update Cache if time has come and then annotates the image by some algorithm creating Image object and attaching Tags to it then storing it to annotation repository.

IABW工作者中的服务缓存更新代码段是:

Service cache update snippet in IABW worker is:

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

IABW每秒被调用很多次,并且在处理器方面相当广泛.

IABW is called many times a second and is pretty processor extensive.

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

While running it for days I found memory increase in task manager. Using Perfmon to watch for Process/Private Bytes and .NET Memory/Bytes in all heaps I found them both increasing over the time.

使用该应用程序进行实验时,我发现缓存更新是问题所在.如果未更新,则内存增加不会有问题.但是,如果Cache更新每1-5分钟进行一次,那么应用程序将很快获得内存.

Experimenting with the application I found that Cache update is the problem. If it is not updated there is no problem with the mem increase. But if the Cache update is as frequent as once in 1-5 minutes application gets ouf of mem pretty fast.

该内存泄漏可能是什么原因?经常创建图像对象,其中包含对Cache中Tag对象的引用.我认为在创建Cache字典时,将来以某种方式不会对这些引用进行垃圾回收.

What might be the reason of that mem leak? Image objects are created quite often containing references to Tag objects in Cache. I presume when the Cache dictionary is created those references somehow are not garbage collected in the future.

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

Does it need to explicitly null managed byte[] objects to avoid memory leak e.g. by implementing Tag, Image as IDisposable?

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

4 aug 2001, addition of the buggy code snippet causing quick mem leak.

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或丢弃任何内容.

No, you don't need to set anything to null or dispose of anything if it's just memory as you've shown.

我建议您掌握一个好的分析器,以找出泄漏的位置.您是否有可能无法处理的与非内存相关的任何内容,例如加载GDI +图片以获取字节?

I suggest you get hold of a good profiler to work out where the leak is. Do you have anything non-memory-related that you might be failing to dispose of, e.g. loading a GDI+ image to get the bytes?

这篇关于内存泄漏问题:处置还是不处置托管资源?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆