From fa2fdbe24ea1e69eed8010b38edca6106a703ef7 Mon Sep 17 00:00:00 2001 From: Moonchild Date: Thu, 19 Sep 2024 21:35:28 +0200 Subject: [PATCH] [Pale-Moon] Issue #1972 - Implement ghostbuster --- application/palemoon/app/profile/palemoon.js | 3 ++ .../palemoon/base/content/tabbrowser.xml | 7 ++++ .../palemoon/components/nsBrowserGlue.js | 33 +++++++++++++++++++ 3 files changed, 43 insertions(+) diff --git a/application/palemoon/app/profile/palemoon.js b/application/palemoon/app/profile/palemoon.js index c2e1cd2cd5..0aba8f1074 100644 --- a/application/palemoon/app/profile/palemoon.js +++ b/application/palemoon/app/profile/palemoon.js @@ -501,6 +501,9 @@ pref("javascript.options.showInConsole", true); pref("general.warnOnAboutConfig", false); #endif +// Enable unlinking of ghost windows so they can be garbage collected. +pref("browser.ghostbuster.enabled", true); + // This is the pref to control the location bar, change this to true to // force this - this makes the origin of popup windows more obvious to avoid // spoofing. We would rather not do it by default because it affects UE for web diff --git a/application/palemoon/base/content/tabbrowser.xml b/application/palemoon/base/content/tabbrowser.xml index 52e39d898b..14cd720f64 100644 --- a/application/palemoon/base/content/tabbrowser.xml +++ b/application/palemoon/base/content/tabbrowser.xml @@ -2134,6 +2134,13 @@ var browser = this.getBrowserForTab(aTab); this._outerWindowIDBrowserMap.delete(browser.outerWindowID); + if (Services.prefs.getBoolPref("browser.ghostbuster.enabled", true)) { + Cu.unlinkGhostWindows(); +#ifdef DEBUG + dump("Unlinking ghost windows has run on tab close.\n"); +#endif + } + // Because of the way XBL works (fields just set JS // properties on the element) and the code we have in place // to preserve the JS objects for any elements that have diff --git a/application/palemoon/components/nsBrowserGlue.js b/application/palemoon/components/nsBrowserGlue.js index 958475a29e..b66881dbf6 100644 --- a/application/palemoon/components/nsBrowserGlue.js +++ b/application/palemoon/components/nsBrowserGlue.js @@ -62,6 +62,10 @@ const BOOKMARKS_BACKUP_INTERVAL = 86400 * 1000; // Maximum number of backups to create. Old ones will be purged. const BOOKMARKS_BACKUP_MAX_BACKUPS = 10; +// Use users' idle time to unlink ghost windows and clean up memory. +// Trigger this by default every 5 minutes. +const GHOSTBUSTER_INTERVAL = 5 * 60; + // Factory object const BrowserGlueServiceFactory = { _instance: null, @@ -82,6 +86,10 @@ function BrowserGlue() { "@mozilla.org/widget/idleservice;1", "nsIIdleService"); + XPCOMUtils.defineLazyServiceGetter(this, "_ghostBusterService", + "@mozilla.org/widget/idleservice;1", + "nsIIdleService"); + XPCOMUtils.defineLazyGetter(this, "_distributionCustomizer", function() { Cu.import("resource:///modules/distribution.js"); return new DistributionCustomizer(); @@ -109,6 +117,7 @@ BrowserGlue.prototype = { _isPlacesShutdownObserver: false, _isPlacesDatabaseLocked: false, _migrationImportsDefaultBookmarks: false, + _isGhostBusterObserver: false, _setPrefToSaveSession: function(aForce) { if (!this._saveSession && !aForce) { @@ -241,6 +250,15 @@ BrowserGlue.prototype = { if (this._idleService.idleTime > BOOKMARKS_BACKUP_IDLE_TIME * 1000) { this._backupBookmarks(); } + if (this._ghostBusterService.idleTime > GHOSTBUSTER_INTERVAL * 1000) { + if (Services.prefs.getBoolPref("browser.ghostbuster.enabled", true)) { + Cu.unlinkGhostWindows(); + Cu.forceGC(); +#ifdef DEBUG + dump("Unlinking ghost windows + GC has run on idle.\n"); +#endif + } + } break; case "distribution-customization-complete": Services.obs.removeObserver(this, "distribution-customization-complete"); @@ -623,6 +641,13 @@ BrowserGlue.prototype = { DateTimePickerHelper.init(); this._trackSlowStartup(); + + // Initialize ghost window idle observer. + if (!this._isGhostBusterObserver) { + this._ghostBusterService.addIdleObserver(this, GHOSTBUSTER_INTERVAL); + // Prevent re-entry. + this._isGhostBusterObserver = true; + } }, /** @@ -639,6 +664,14 @@ BrowserGlue.prototype = { FormValidationHandler.uninit(); AutoCompletePopup.uninit(); this._dispose(); + + // Shut down ghost window idle observer. + if (this._isGhostBusterObserver) { + this._ghostBusterService.removeIdleObserver(this, GHOSTBUSTER_INTERVAL); + this._isGhostBusterObserver = false; + } + // Do one final unlink to combat shutdown issues. + Cu.unlinkGhostWindows(); }, // All initial windows have opened.