Memory Leak in Aspose Slides 20.5

We are facing issues of com.aspose.slides.Presentation objects not getting garbage collected and hence blocking a huge amount of memory. This does not happen to all presentation objects that have been created, but to some. So unfortunately I cannot reproduce it.

After waiting several hours and performing multiple garbage collections, the com.aspose.slides.Presentation objects still remain in memory, although they are not used anymore by my application.

Looking at the nearest GC roots, it always reveals the same:
grafik.png (12.3 KB)
The class com.aspose.slides.ag6 looks very suspicious. It contains a static Stack which is only accessible via methods that contain synchronized blocks. That’s why I assume this is built for multi-threaded purposes. This whole construct can clearly can lead to memory leaks if the stack content does not get removed with absolute certainty.

Please investigate and also tell me if there is a temporary workaround to clean up this static stack. If I knew what ag6 was used for, it would maybe also help me to reproduce it.

Operating System: Windows 10
Aspose Slides Java 20.5

@pstoehrer,

I have observed the issue shared by you and like to share that if there would be a memory leak then it must be reproduced for all presentation decks. Can you please share the details of the issue in the form of sample presentation, used sample code and snapshot of the claim exhibiting memory leak. As without provision of these it will not be possible for us to investigate the issue.

One suggestion that I would like to add here is to use the finally block in your code where you must explicitly dispose the Presentation object as a good practice too.

I am now able to reproduce it with a simple program. Before exiting with ENTER, create a heap dump of the small program. It will contain the leaked Presentation objects.
And calling presentation.dispose() does not help apparently.

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;

import com.aspose.slides.FillType;
import com.aspose.slides.IAutoShape;
import com.aspose.slides.IColorFormat;
import com.aspose.slides.ISlide;
import com.aspose.slides.PatternStyle;
import com.aspose.slides.Presentation;
import com.aspose.slides.SaveFormat;
import com.aspose.slides.ShapeType;

public class Main {
    private static final int PRESENTATIONS = 100;

    public static void main(String[] args) {
        for (int i = 0; i < PRESENTATIONS; i++) {
            createPresentation("file_" + i);
        }

        try {
            System.out.println("");
            System.out.println("Press ENTER to exit!");
            System.in.read();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static void createPresentation(final String name) {
        final Presentation presentation = new Presentation();
        try {
            final ISlide slide = presentation.getSlides().get_Item(0);
            addTriangle(slide, 60);

            final File pptxFile = new File(name + ".pptx");

            try (final FileOutputStream outputStream = new FileOutputStream(pptxFile)) {
                System.out.println("Writing file " + pptxFile.getAbsolutePath());
                presentation.save(outputStream, SaveFormat.Pptx);
            } catch (IOException e) {
                e.printStackTrace();
            }

            try {
                System.out.println("Deleting file " + pptxFile.getAbsolutePath());
                Files.deleteIfExists(pptxFile.toPath());
            } catch (IOException e) {
                e.printStackTrace();
            }
        } finally {
            presentation.dispose();
        }
    }

    private static void addTriangle(final ISlide slide, final float y) {
        final IAutoShape shape = slide.getShapes().addAutoShape(ShapeType.Triangle, 310, y, 100, 100);
        final IColorFormat foreColor = slide.getPresentation().getMasterTheme().getColorScheme().getAccent1();
        final IColorFormat backColor = slide.getPresentation().getMasterTheme().getColorScheme().getLight1();
        shape.getFillFormat().setFillType(FillType.Pattern);
        shape.getFillFormat().getPatternFormat().setPatternStyle(PatternStyle.Vertical);
        shape.getFillFormat().getPatternFormat().getForeColor().copyFrom(foreColor);
        shape.getFillFormat().getPatternFormat().getBackColor().copyFrom(backColor);
    }
}

The heap dump from my machine is unfortunately too big to upload.

@pstoehrer,

Thank you for sharing the sample code. However, we need source presentation files (if any) reproducing the issue along with heap dump. You can upload them on some file server and share the download link with us. Please also provide the Java, Operating System and Heap setting details as well on your end.

What do you mean with source presentation file? I didn’t use one, I’m just creating simple presentations with one slide and a shape on it.

I uploaded the heap dump here: (Created with JVisualVM)
https://1drv.ms/u/s!AsqmrkkpiA6IiyIM7e8ceCqnITZB?e=tlpdrS

OS:
Microsoft Windows 10 Pro
Version: 10.0.18363 Build 18363

Java:
openjdk version “1.8.0_232”
OpenJDK Runtime Environment (build 1.8.0_232-b09)
OpenJDK 64-Bit Server VM (build 25.232-b09, mixed mode)

Heap Size: 831 MB
Running with JVM defaults, no JVM parameter was set.

@pstoehrer,

Thank you for sharing the information with us for review. A ticket with ID SLIDESJAVA-38138 has been created to further investigate this and we will share the feedback with you as soon as it will be addressed.

The issues you have found earlier (filed as SLIDESJAVA-38138) have been fixed in this update.

@mudassir.fayyaz
So what does this mean now? Was there a memory leak fixed or was only the investigation completed? The release notes and this notification here are not really clear.
I tested with Aspose Slides 20.7 and could not reproduce the described behavior. So I assume I was correct with my assessment that there was a memory leak and that it was fixed now.

@pstoehrer,

After carrying out investigation on our end we are unable to find the leak in classical terms, but did found some ‘static final’ caches that can be disposed (their life cycle is too long). For this reason, our results are so different in 20.5/20.6 for 1000, 2000 and 3000 iterations. We have fixed it for Aspose.Slides for Java 20.7.

Old result (Aspose.Slides for Java 20.5/20.6):

Iterations Heap Dump size (in bytes)
1000 ~155,147,331
2000 ~170,209,001
3000 ~114,291,312

New result (Aspose.Slides for Java 20.7):

Iterations Heap Dump size (in bytes)
1000 ~61.272.076
2000 ~61.615.881
3000 ~61.350.534
1 Like