Copy link to clipboard
Copied
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
Copy link to clipboard
Copied
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
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
Oh gosh, yes obviously 😛
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
Ok. But do try without repeated declarations. "Shouldn't be a problem" doesn't really cut it with InDesign scripting. And remember that you're better off with ExtendScript for the time being.
Copy link to clipboard
Copied
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