sungaila / PDFtoImage

A .NET library to render PDF files into images.
https://www.sungaila.de/PDFtoImage/
MIT License
144 stars 14 forks source link

In-Use memory increasing every time when you load a new page #76

Closed Raja-1250 closed 4 months ago

Raja-1250 commented 4 months ago

PDFtoImage version

4.0.0

OS

Windows

OS version

Hololens 2

Architecture

arm64

Framework

.NET Framework

App framework

UWP

Detailed bug report

Hi @sungaila The memory usage is consistently growing with each new page load, suggesting that certain unreferenced objects are not being properly disposed of in the code. Consequently, the application crashes after loading several pages. On Hololens 2, the crash occurs after loading 40 pages, with an observed increase of around 20 MB in used memory per new page. On an Android phone, the app crashes after loading 15 pages. It's worth noting that I'm setting the Encode quality to 1000. Below is the code snippet used for loading a page.

 private async Task GetPage(int pageNo, MemoryStream pdfStream,OnPDFImageLoaded onPDFImageLoaded)
    {
        try
        {
            await Task.Run(() =>
            {
                MemoryStream imageStream = new MemoryStream();
                SKBitmap img = PDFtoImage.Conversion.ToImage(pdfStream, true, null, pageNo);
                img.Encode(imageStream, SKEncodedImageFormat.Png, quality);
                onPDFImageLoaded?.Invoke(true,"Success",imageStream);
            });
        }
        catch (Exception e)
        {
            onPDFImageLoaded?.Invoke(false, "Reason to fail:"+e.ToString(), null);
        }
    }
sungaila commented 4 months ago

Hi @Raja-1250, where do you dispose imageStream in the above code snippet? I can see it is put into onPDFImageLoaded with no further context.

Also your img is not disposed either. Maybe change this line into

using SKBitmap img = PDFtoImage.Conversion.ToImage(pdfStream, true, null, pageNo);
Raja-1250 commented 4 months ago

@sungaila I'm disposing the imageStream in my caller method after consuming it, Using your suggested line of code didn't help, Also i've tried img.Dispose(), still no luck.

sungaila commented 4 months ago

What about pdfStream? You are calling ToImage with the parameter leaveOpen: true so you have to dispose this one somewhere as well.

Raja-1250 commented 4 months ago

@sungaila I load the PDF file into pdfStream just once for the entire session, and I dispose of it before closing the app. Therefore, it shouldn't cause in a consistent increase in the in-use memory value.

sungaila commented 4 months ago

I couldn't reproduce a memory leak with this simple setup:

using var input = new FileStream("SocialPreview.pdf", FileMode.Open, FileAccess.Read);

for (int i = 0; i < 1000; i++)
{
    using var bitmap = PDFtoImage.Conversion.ToImage(input, leaveOpen: true);
}
image

No idea how Unity handles the garbage collection, but if you are sure you dispose your two streams and one SKBitmap properly, maybe you could try to force collection yourself:

GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
Raja-1250 commented 4 months ago

@sungaila I was able to resolve this issue by using Resources.UnloadUnusedAssets(). This API manually triggers the process of unloading assets like textures, models and etc that are no longer referenced by any active objects in the scene.