I decided to try to use yield in my project and ran into a memory leak problem.

Here is a sample code using 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); } } 

But without:

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

Result processing code:

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

In the first case, I get a memory leak on every call, in the second there is none. All memory is correctly released without using GC, since the ExportImage structure is from the C library, so GC is probably not advisable to blame for this.

What could be the problem? For I would like to use yield , but if such difficulties arise with it, then there is no sense. I understand that it is somewhere that I am doing something wrong, but I cannot understand. So I am waiting for hints.

PS I can assume that when you call tmpres.ToArray() somewhere there is a leak, but how to get rid of it?

  • Two questions. What are frames? What does ProcessSingleExportImageCropSrc return and shouldn't it be released too? - Pavel Mayorov

1 answer 1

In fact, the leak happens here: tmpres.Count() . Most likely, the result of calling ProcessSingleExportImageCropSrc from you, but I can be wrong.

Calling Count() leads to the complete execution of your generator, opens up a bunch of resources - which you never close!

It is more correct to write external code like this:

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

Note: there is only one materializing call, ToArray() , the second call is not done.