yield MemoryLeaks

252
08 марта 2018, 08:49

Решил я попробовать использовать yield в своем проекте и столкнулся с проблемой утечки памяти.

Вот пример кода с использованием yield:

public IEnumerable<ExportImage> ProcessMultipleExportImagesMultipleSrcCrop(IEnumerable<ExportImage> bitmaps)
    {
        int nok = 1;
        foreach (var pos in Settings.ImagesReferences)
        {
            nok = NOK(nok, pos.Length);
        }
        nok = NOK(nok, bitmaps.Count());
        for (int i = 0; i < nok; i++)
        {
            yield return ProcessSingleExportImageCropSrc(bitmaps.ElementAt(i % bitmaps.Count()), i);
        }
    }

А вот без:

public IEnumerable<ExportImage> ProcessMultipleExportImagesMultipleSrcCrop(IEnumerable<ExportImage> bitmaps)
    {
        int nok = 1;
        foreach (var pos in Settings.ImagesReferences)
        {
            nok = NOK(nok, pos.Length);
        }
        nok = NOK(nok, bitmaps.Count());
        var res = new List<ExportImage>();
        for (int i = 0; i < nok; i++)
        {
            res.Add( ProcessSingleExportImageCropSrc(bitmaps.ElementAt(i % bitmaps.Count()), i));
        }
        return res;
    }

Код обрабатывающий результат:

var tmpres = ImageConcatenator.ProcessMultipleExportImagesMultipleSrcCrop(frames);
            var res = new SafeIntPtrArray<ExportImage> { Values = tmpres.ToArray(), Size = tmpres.Count() };
            foreach (var item in frames)
            {
                item.Dispose();
            }
            await Render(res);

В первом случае я получаю утечку памяти при каждом вызове, во втором нет. Вся память корректно освобождается без использования GC, так как ExportImage структура из C библиотеки, так что GC винить в этом наверное не целесообразно.

В чем может быть проблема? Ибо хотелось бы использовать yield, но если с ним такие трудности возникают, то толка нету. Я понимаю, что это я где-то неверно что-то неправильно делаю, но понять не могу. Так что жду подсказки.

P.S. Могу предположить, что при вызове tmpres.ToArray() где-то там и происходит утечка, но как от нее избавиться?

Answer 1

На самом деле утечка происходит вот тут: tmpres.Count(). Скорее всего, у вас утекает результат вызова ProcessSingleExportImageCropSrc, но могу и ошибаться.

Вызов Count() приводит к полному выполнению вашего генератора, открывается куча ресурсов - которые вы никогда не закрываете!

Правильнее внешний код писать вот так:

var tmpres = ImageConcatenator.ProcessMultipleExportImagesMultipleSrcCrop(frames).ToArray();
var res = new SafeIntPtrArray<ExportImage> { Values = tmpres, Size = tmpres.Length };
foreach (var item in frames)
{
    item.Dispose();
}
await Render(res);

Обратите внимание: материализующий вызов - только один, ToArray(), второго вызова не делается.

READ ALSO
Как ограничить вывод значения

Как ограничить вывод значения

У меня есть переменная типа float, у которой после запятой много цифрМне хотелось бы ограничить её до одного знака после запятой

293
Ошибка при считывании файла ресурсов WinForms C#

Ошибка при считывании файла ресурсов WinForms C#

При загрузке, даже стандартного WindowsForm, ничего еще не меняя, уже вылезает ошибка, как от нее избавиться? И почему она вылезает, если ничего...

250
Как получить ID больше, чем у 50 видео?

Как получить ID больше, чем у 50 видео?

Здравствуйте! Пытаюсь получить идентификаторы более, чем у 50 роликов, используя nextPageTokenНо проблема в том, что каждый раз в переменную ids добавляются...

234
Передача данных из класса в textBox

Передача данных из класса в textBox

Есть программа которая сравнивает строки по датеНеобходимо чтобы в textBox отображался процесс работы программы, а именно выводились найденные...

257