Closed Bug 1354820 Opened 7 years ago Closed 2 years ago

Implement a module getter that will unload when idle

Categories

(Firefox :: General, enhancement)

enhancement
Not set
normal

Tracking

()

RESOLVED WONTFIX

People

(Reporter: mccr8, Unassigned)

References

Details

(Whiteboard: [overhead:?])

Attachments

(1 file)

Some .jsms are needed only temporarily, such as those used to find in a page, open the content menu, or view a PDF. They should be unloaded when they haven't been needed for a while.

This can be implemented with a special XPCOMUtils module getter that records when it is used. Periodically, a timer unloads any modules imported in this way that have not been recently used.

This should be extended to cover message listeners and observers. It should also support a way for a module to clone state into the central unloader service, so that it can be reconstituted after being reloaded.
Here's a simple prototype that only deals with the module getter case, and does not deal with state. The unload time is 5 seconds to make testing easier. I use it for NLP.jsm, which is a simple module used by the finder that implements a single method.
One potential pitfall is that if one place does Cu.import() and another uses the idle unloader, it'll get unloaded out from under the former consumer and break things. I don't know if there's any easy way to detect that.
(In reply to Andrew McCreight [:mccr8] from comment #3)
> One potential pitfall is that if one place does Cu.import() and another uses
> the idle unloader, it'll get unloaded out from under the former consumer and
> break things. I don't know if there's any easy way to detect that.

One solution I thought of would be to add a new method, called something like Cu.unloadableImport(). This would be the same as import(), except that it would require the presence of a new property UNLOADABLE on the jsm. import() would be modified to ensure there is no UNLOADABLE property present. Thus we would ensure that a jsm would only be loaded via one or the other import. Somebody could still get themselves into trouble by calling unloadableImport() without the unloadable framework, but it would avoid spooky action at a distance.
This version fixes some bugs. It also requires unloadable modules specify a Reconstitutable property. A jsm is only unloaded if this return true. That seems to work well for getting unloading working for FinderIterator: basically, you only allow unloading if it isn't actively iterating over whatever. Then there's no state to save. I tried doing something similar for FinderHighlighter, but that seems to leave entries in its global weak map even when there is no active highlighting, so it does not get unloaded.
Another consideration is that Cu.unload() is dangerous to use with a factory pattern jsm. For instance, Color.jsm just implements a class, so people can do "new Color()". I believe that any such object will keep the Color.jsm compartment alive via the prototype, but access to the prototype in this way will not be tracked by the special Color property on the global added by XPCOMUtils.

Calling unload does not actually unload the jsm, it drops the XPConnect component manager's strong reference and the mapping from the resource URI to the component. Thus if we call unload on Color.jsm, I think we would end up loading many copies of Color.jsm, which is bad. One approach would be to nuke a compartment when we unload it, which would cause breakage when used in this way. Another approach would be to make unloading keep the registry entry, but change the strong reference to a weak reference.
Depends on: 1355215
See Also: → 1358921
I've been thinking about something like this too.

It would be nice if we could have the module loader store weak references to the module global for safely unloadable modules, and then the XPCOMUtils lazy getter could just Cu.import them on every access, which would reload the module when needed, rather than replacing the getter with a static property, which would keep it alive.

It might not even be necessary to mark the modules unloadable, in that case, since any that actually needed to be kept alive would probably be kept alive by an external reference.
Whiteboard: [overhead:noted]
Andrew, do you have an idea of what magnitude of savings this could have?
Flags: needinfo?(continuation)
Whiteboard: [overhead:noted] → [overhead:?]
It depends on which scripts we could discard, and nobody has looked into that.
Flags: needinfo?(continuation)

I never got very far with my prototype here. It always just felt a little too risky because there are a lot of heuristics that could really mess things up if you got them wrong.

Assignee: continuation → nobody

Comment 11 still applies. Content process JSM overhead shouldn't be that bad nowadays.

Status: NEW → RESOLVED
Closed: 2 years ago
Resolution: --- → INCOMPLETE
Resolution: INCOMPLETE → WONTFIX
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: