Skip to main content
Participant
December 11, 2022
Question

Memory leak iterating collections

  • December 11, 2022
  • 2 replies
  • 845 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.

Loic.Aigon
Legend
December 12, 2022

Oh gosh, yes obviously 😛

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