Aspose.Slides for Java: Memory Leak in slides.addClone Method

When I have a large presentation (also works with small, but with large ones it’s more obvious.
It happens when I try to split a presentation into it’s slides. See my testcode:

package de.testaspose

import com.aspose.slides.LoadOptions
import com.aspose.slides.Presentation
import com.aspose.slides.PresentationLockingBehavior
import com.aspose.slides.SaveFormat

fun main() {
    val loadOptions = LoadOptions()
    loadOptions.blobManagementOptions.presentationLockingBehavior = PresentationLockingBehavior.KeepLocked;
    loadOptions.blobManagementOptions.isTemporaryFilesAllowed = true;
    loadOptions.blobManagementOptions.tempFilesRootPath = "/Users/arturhellmann/DEV/tests/data/"
    loadOptions.blobManagementOptions.maxBlobsBytesInMemory = 10 * 1024 * 1024; // 10 MB

    val presName = "TestPres"

    val sourcePresentation = Presentation(
        "/Users/arturhellmann/DEV/tests/data/${presName}.pptx",
        loadOptions
    )

    var mostUsedHeap = 0.0

    sourcePresentation.slides.forEach { slideToKeep ->

        val newPresentation = Presentation()

        newPresentation.slides.removeAt(0)
        newPresentation.masters.removeAt(0)
        newPresentation.slides.addClone(slideToKeep) // Only this line leads to a memory peak.

        newPresentation.save(
            "/Users/arturhellmann/DEV/tests/data/result/TestPres_${slideToKeep.slideNumber}.pptx", SaveFormat.Pptx
        )

        val usedHeap = (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()).toDouble() / 1024 / 1024
        println("Used heap size: $usedHeap MB in slide ${slideToKeep.slideNumber}")
        mostUsedHeap = if (usedHeap > mostUsedHeap) usedHeap else mostUsedHeap

        newPresentation.dispose()

        System.gc()

    }
    println("Most used heap size: $mostUsedHeap MB")

    sourcePresentation.dispose()

    System.gc()

    readLine()
}

Using .addClone(...) leads to accumulating memory that will not be cleaned. Just closing the sourcePresentation by sourcePresentation.dispose() does release the memory. so it is not really a memoryleak, but it’s keeping a large bunch of memory as long as the presentation is open.

But that means that iterating over large presentations is really memory consuming.

My workaround for now is to always close the source presentation and reopen it, like so:

import com.aspose.slides.LoadOptions
import com.aspose.slides.Presentation
import com.aspose.slides.PresentationLockingBehavior
import com.aspose.slides.SaveFormat

fun main() {
    val loadOptions = LoadOptions()
    loadOptions.blobManagementOptions.presentationLockingBehavior = PresentationLockingBehavior.KeepLocked;
    loadOptions.blobManagementOptions.isTemporaryFilesAllowed = true;
    loadOptions.blobManagementOptions.tempFilesRootPath = "/Users/arturhellmann/DEV/dockertests/data/"
    loadOptions.blobManagementOptions.maxBlobsBytesInMemory = 10 * 1024 * 1024; // 10 MB

    val presName = "TestPres"

    val sourcePresentation = Presentation(
        "/Users/arturhellmann/DEV/dockertests/data/${presName}.pptx",
        loadOptions
    )

    val numberOfSlides = sourcePresentation.slides.size()

    sourcePresentation.dispose()

    var mostUsedHeap = 0.0

    for (index in 0 until numberOfSlides) {

        val sourcePresentation = Presentation(
            "/Users/arturhellmann/DEV/dockertests/data/${presName}.pptx",
            loadOptions
        )

        val slideToKeep = sourcePresentation.slides.get_Item(index)

        val newPresentation = Presentation()

        newPresentation.slides.removeAt(0)
        newPresentation.masters.removeAt(0)
        newPresentation.slides.addClone(slideToKeep) // Only this line leads to a memory peak.

        newPresentation.save(
            "/Users/arturhellmann/DEV/dockertests/data/result/TestPres_${slideToKeep.slideNumber}.pptx", SaveFormat.Pptx
        )

        val usedHeap = (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()).toDouble() / 1024 / 1024
        println("Used heap size: $usedHeap MB in slide ${slideToKeep.slideNumber}")
        mostUsedHeap = if (usedHeap > mostUsedHeap) usedHeap else mostUsedHeap

        newPresentation.dispose()
        sourcePresentation.dispose()

        System.gc()

    }
    println("Most used heap size: $mostUsedHeap MB")

    sourcePresentation.dispose()

    System.gc()

    readLine()
}

But for large files, this is obviously seriously slow…

Is there some better way to iterate over slides and add them to new presentations, or maybe a native split presentation method like in the cloud api?

Regards

Artur

@a.hellmann

• Is the memory accumulation happening during the addClone() operation itself, or is it related to how the cloned slide references are maintained in memory?
• Are you observing the same memory behavior when using clone() instead of addClone()?
• Does the issue persist if you explicitly call System.gc() immediately after newPresentation.dispose()?
• What specific version of Aspose.Slides for Java/Kotlin are you using, and is this behavior consistent across different presentation file sizes?
• Have you tested alternative approaches like using Presentation.clone() or Slide.clone() methods directly?
• Is the temporary file management configuration sufficient to handle the memory pressure, or could the issue stem from internal caching mechanisms?

It happens exactly on the addClone call. The slide seems not to be restrained because disposing the targetPresentation does not clean the memory, the source Presentation.dispose does.

• Are you observing the same memory behavior when using clone() instead of addClone() ?

The java sdk seems not to have any .clone methods. Neither on the slide, nor on the presentation.

• Does the issue persist if you explicitly call System.gc() immediately after newPresentation.dispose() ?

Yes, only disposing the source Presentation does the trick.

• What specific version of Aspose.Slides for Java/Kotlin are you using, and is this behavior consistent across different presentation file sizes?

25.9, but also 24.1.
The issue is consistent, but it appears really when you have large presentations. Especially ones where one slide has large media files (videos for example).
It seems that the sourcePresentation loads those media files asynchronously when needed, but then never releases them, even if the slide is not needed anymore. Is there a way to dispose a slide or clear the caches of a presentation without closing and reopening them?

I mean, in my second example. where I close and open the sourcePresentation on every loop, those single slides still use a lot space, which makes sense, but then it does not accumulate that much.

It’s also not liniar. So when one slide did take 1G in RAM, and the next takes 1.2G it’s not that after this it takes 2.2G. But more like from that moment on there seems some kind of base usage that does not disappear. As said, especially on those slides with big media files.

• Is the temporary file management configuration sufficient to handle the memory pressure, or could the issue stem from internal caching mechanisms?

It seems to be some internal mechanism. Removing the blobManagementOptions does blow up the usage a lot. But it seems not to accumulate, it’s just high from the beginning. So it seems that the presentation is loading some media from it’s temp files, and then just not removes it properly when not needed anymore.

@a.hellmann

• Is the memory leak specifically tied to large media files within slides, or does it occur with all slide content types?
• Does the issue manifest when cloning slides from presentations with minimal media content?
• Are the cloned slides being properly dereferenced after use, or are references being retained elsewhere?
• What is the exact sequence of operations between clone, disposal, and garbage collection?
• How does the memory usage pattern differ between presentations with and without asynchronous media loading enabled?
• Is there a known method to explicitly clear media cache or unload resources from a presentation without full disposal?

@a.hellmann,
We are sorry you encountered this problem. Could you please share a sample presentation file? You can zip the file and upload the archive here or share a link to the file saved in a file storage (Google Drive, Dropbox, etc.).