Memory consumption after rendering certain amount of pdfs
See original GitHub issueBefore you start - checklist
- [x ] I followed instructions in documentation written for my React-PDF version
- [x ] I have checked if this bug is not already reported
- [x ] I have checked if an issue is not listed in Known issues
Description
After rendering certain amount of pdfs we see memory consumption is constantly growing and memory is never released.
According to chrome profiler most memory usage is due to
MessageHandler._onComObjOnMessage method
Here is a screenshot of profiling results
Its probably related to pdf.js itself, so first I filed an issue on pfd.js project.
It was reviewed and the result is that they dont consider this memory leak, unless react-pdf implementation doesn’t invoke ‘destroy’ method for ‘loadingTask’
And I see destroy for loadingTask is never invoked.
Here was my question to pdf.js
Is it right that we MUST call destroy() to avoid memory consumption and if we don’t it may lead to situation above?
And here is pdf.js guys answer to it
The loadingTask must be destroy()-ed in order to clean-up various resources, both on the main- and worker-threads.
I tried brief implementation of ‘destroy’ this way
// utils.js
export const makeCancellable = (promise) => {
let isCancelled = false;
const wrappedPromise = new Promise((resolve, reject) => {
promise.then(
(...args) => (isCancelled ? reject(new PromiseCancelledException('Promise cancelled')) : resolve(...args)),
error => (isCancelled ? reject(new PromiseCancelledException('Promise cancelled')) : reject(error)),
);
});
return {
promise: wrappedPromise,
cancel() {
isCancelled = true;
},
destroy() {
if (typeof promise.destroy === 'function') {
promise.destroy();
}
},
};
};
// Document,jsx
componentWillUnmount() {
this.runningTask.destroy();
cancelRunningTask(this.runningTask);
}
Its probably playing around of promises which is not right way to handle it, but anyway, it leads to no memory consumption,
promise
is an instance of LoadingTask
(PDFJS.getDocument(source)) and promise.destroy()
is successfully invoked and releases resources, but is causing this error from time to time and i think its due my misunderstanding when is must be invoked.
pdf.worker.js:22726 Uncaught (in promise) Error: Worker was terminated
at ensureNotTerminated (pdf.worker.js:22726)
at onFailure (pdf.worker.js:22866)
I have selenium long running test, that shows memory is released with destroy method invoked, and is not released without it.
I think I dont understand the right pdf rendering flow to get loadingTask destroyed when it must be, but I believe this must be invoked as guys from pdf.js confirm this. Can we try clarifying the right flow - when loading task can be destroyed and is it finally the right approach to free resources.
this.runningTask = makeCancellable(PDFJS.getDocument(source));
this is pdf.js API wrapped into cancellable promise, and this API has ‘destroy’ method, that I referenced with a link earlier and that we never invoke.
Steps to reproduce
Steps to reproduce the behavior:
- Render pdf document with Document component.
- While rendering has not yet finished, unmount Document component and mount it again with new pdf source.
- See memory consumption
Expected behavior
Expect to see memory released
Additional information
Environment
- Chrome 70.0
- React-PDF version 3.0.5
- React version 16.2.0
Issue Analytics
- State:
- Created 5 years ago
- Comments:9 (4 by maintainers)
@wojtekmaj I will try within a few hours and give our feedback. Thanx much for participating! We very appreciate your help.
Please kindly check React-PDF
v5.3.0-beta.2
, in which improvements regarding memory management were made.Let me know what you think in #748!