-
Notifications
You must be signed in to change notification settings - Fork 385
Description
Hello,
I believe I have found some memory leaks in version 5.1.10 of the web viewer. Tested on Windows Server 2016 running Chrome 75.
In src/helpers/loadScript.js there is a window.addEventListener('message'... call that isn't properly unsubscribed:
const loadConfig = () => {
const _loadConfig = (e, resolve) => {
if (e.data.type === 'responseConfig') {
loadScript(
e.data.value,
'Config script could not be loaded'
).then(() => {
window.removeEventListener('message', _loadConfig);
resolve();
});
}
};
return new Promise(resolve => {
window.addEventListener('message', e => _loadConfig(e, resolve));
if (process.env.NODE_ENV === 'development') {
loadScript(getHashParams('config', '')).then(() => {
window.removeEventListener('message', _loadConfig);
resolve();
});
}
window.parent.postMessage('requestConfig', '*');
});
};The code is adding an event listener to an anonymous function but is then trying to remove _loadConfig which is not subscribed to window.addEventListener.
The code should be changed to something like:
const loadConfig = () => {
return new Promise(resolve => {
const _loadConfig = (e) => {
if (e.data.type === 'responseConfig') {
loadScript(
e.data.value,
'Config script could not be loaded'
).then(() => {
window.removeEventListener('message', _loadConfig);
resolve();
});
}
};
window.addEventListener('message', _loadConfig);
if (process.env.NODE_ENV === 'development') {
loadScript(getHashParams('config', '')).then(() => {
window.removeEventListener('message', _loadConfig);
resolve();
});
}
window.parent.postMessage('requestConfig', '*');
});
};There are also two issues causing memory leaks in webviewer.js (one similar to the above, and one due to closing over options:
window.WebViewer.l = function() {
return options.l || options.licenseKey;
};
window.WebViewer.workerTransportPromise = function() {
return options.workerTransportPromise;
};
var me = this;
window.addEventListener('message', function(event) {
if (event.source !== me.iframe.contentWindow) {
return;
}
if (event.data === 'requestl') {
event.source.postMessage({
type: 'responsel',
value: options.l || options.licenseKey
}, '*');
}
if (event.data === 'requestConfig') {
var configURL = options.config
? me._correctRelativePath(options.config)
: '';
event.source.postMessage({
type: 'responseConfig',
value: configURL
}, '*');
}
}, false);The window.WebViewer.l and window.WebViewer.workerTransportPromise function assignments are causing memory leaks. Changing those lines to:
window.WebViewer.l = function() {
return this.options.l || this.options.licenseKey;
};
window.WebViewer.workerTransportPromise = function() {
return this.options.workerTransportPromise;
};somewhat but does not fully mitigate the memory leaks (this.options is still closed over, causing a small leak) - I believe one way to fully mitigate this would be to set objects instead of functions.
The window.addEventListener('message',... code has a similar problem to the loadScript.js code. One fix is to change the code to:
var me = this;
var licenseKeyListener = function(event) {
if (event.source !== me.iframe.contentWindow) {
return;
}
if (event.data === 'requestl') {
event.source.postMessage({
type: 'responsel',
value: options.l || options.licenseKey
}, '*');
window.removeEventListener('message', licenseKeyListener);
}
}
var configListener = function(event) {
if (event.source !== me.iframe.contentWindow) {
return;
}
if (event.data === 'requestConfig') {
var configURL = options.config
? me._correctRelativePath(options.config)
: '';
event.source.postMessage({
type: 'responseConfig',
value: configURL
}, '*');
window.removeEventListener('message', configListener);
}
}
window.addEventListener('message', licenseKeyListener, false);
window.addEventListener('message', configListener , false);(assuming that the license and options don't need to be sent to the window multiple times - if they need to be sent multiple times then a more complex mitigation will be required).
Currently I am observing a ~10mb memory leak each time I load the PDF viewer - which is a rather catastrophic memory leak. With these changes the leaks become small but not necessarily non-existent (I think my changes fully fix the window.addEventListener issues but not the other issues). I was not experiencing these memory leaks with version 5.0.0 of the viewer.