Проблемы утечки памяти: утилизировать или не утилизировать управляемые ресурсы? - PullRequest
0 голосов
/ 03 августа 2011

Я испытываю странную утечку памяти в дорогостоящем приложении для поиска изображений на основе контента (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-памятью / байтами во всех кучах, я обнаружил, что они оба увеличиваются со временем.

Экспериментируя с приложением, я обнаружил, что проблема заключается в обновлении кэша. Если он не обновляется, проблем с увеличением памяти нет. Но если обновление Cache происходит так часто, как раз в 1-5 минут, приложение довольно быстро выходит из памяти.

Что может быть причиной этой утечки памяти? Объекты изображений создаются довольно часто, содержащие ссылки на объекты Tag в Cache. Я предполагаю, что при создании словаря Cache эти ссылки как-то не собираются в будущем.

Нужно ли явно обнулять управляемые объекты byte [], чтобы избежать утечки памяти, например путем реализации Tag, Image как IDisposable?

Редактировать: 4 августа 2001 года, добавление фрагмента кода с ошибкой, вызывающего быструю утечку памяти.

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

1 Ответ

1 голос
/ 03 августа 2011

Нет, вам не нужно ничего устанавливать на ноль или утилизировать что-либо, если это просто память, как вы показали.

Я предлагаю вам воспользоваться хорошим профилировщиком, чтобы решить, где происходит утечкаявляется.Есть ли у вас что-то не относящееся к памяти , которое вы, возможно, не смогли бы утилизировать, например, загрузили изображение GDI + для получения байтов?

...