Skip to main content
Participant
December 11, 2022
Question

Memory leak iterating collections

  • December 11, 2022
  • 2 replies
  • 847 views

Hello,

 

I have a UXP script that iterates over all TextStyleRanges of all Paragraphs of all PageItems of all Pages of a document, and it seems to be leaking memory.

My document has 140 pages, each page has 1-3 page items, each having 15-20 paragraphs with a few TextStyle ranges each. At about 20 pages, memory consumption is already 4GB and it quickly grows to 100%, at which point the entire process slows down so much that it takes hours to process the entire document.

I feel like the collections provide only a facade to InDesign object, which are only created as needed, except once they are created they remain in memory.

Is there any way to release a collection to reclaim the memory? Or any other workarounds?

 

For reference, here is how I am iterating over my document:

const pages = app.activeDocument.pages.everyItem().getElements();
  for(let iPage = 0; iPage < 20; iPage++){
    const page = pages[iPage];
    const pageItems = page.allPageItems;
    for(let iPageItem = 0; iPageItem < pageItems.length; iPageItem++){
      const pageItem = pageItems[iPageItem];
      if (!pageItem.paragraphs) {
        continue;
      }
      const paragraphs = pageItem.paragraphs.everyItem().getElements();
      for (let iParagraph = 0; iParagraph < paragraphs.length; iParagraph++){
        const paragraph = paragraphs[iParagraph];
        const ranges = paragraph.textStyleRanges.everyItem().getElements();
        for (let iRange = 0; iRange < ranges.length-1; iRange ++){
          const range = ranges[iRange];
        }
      }
    }
  }

Any help is much appreciated 🙂

David

This topic has been closed for replies.

2 replies

Peter Kahrel
Community Expert
Community Expert
December 12, 2022

Or even shorter:

const ranges = app.activeDocument.stories.everyItem().textStyleRanges.everyItem().getElements();

The memory leak you see may be caused by the repetitive const declarations inside the loops.  See what happens when you declare them as variables outside the loops, at the beginning of the script.

 

And finally, UXP scripting is still work in progress, it'll get better over time. At the moment ExtendScripts are considerably quicker than equivalent UXP scripts when they make heavy use of InDesign's DOM. Pure JavaScript is quicker in UXP, but since every InDesign script touches the DOM for the time being you'll be better off with ExtendScript.

Participant
December 12, 2022

Hi Peter,

Thanks for your reply. I unfortunately can't use your one liner since I need to keep track of the relationship between testStyleRanges and their paragraphs and their pages. The code I posted was to illustrate the issue, but I do actually need some info from the page and paragraph in my script.

Repeated declarations really shouldn't be a problem since they would get garbage collected as soon as they fall out of scope.

Loic.Aigon
Legend
December 12, 2022

Hi,

 

Re. "I need to keep track of the relationship between testStyleRanges and their paragraphs and their pages.". Starting from Peter's one-liner, you can access the paragraphs collection. And keep climbing up to the page. Not sure what would be the quickest though.

Loic

Loic

Loic.Aigon
Legend
December 12, 2022

UXP brought modern ES6 syntax so why not use it 😉 I don't know if that would solve your memory leak issue but it could discard the chain of loops you are using. Give it a try and see:

function main(){
  let pages = app.activeDocument.pages.everyItem().getElements();
  pages.forEach( page => {
    let pageItems = page.allPageItems;
    pageItems.forEach( pageItem => {
      if(pageItem.hasOwnProperty("paragraphs")){
        let paragraphs = pageItem.paragraphs.everyItem().getElements();
        paragraphs.forEach( paragraph=> {
          let ranges =  paragraph.textStyleRanges.everyItem().getElements();
          ranges.forEach( range => {
            console.log(range);
          })
        })
      }
    });
  })
}

main();

HTH

Loic