Closed Bug 1486596 Opened 8 years ago Closed 8 years ago

GeckoSession can leak a Gecko window

Categories

(GeckoView :: General, enhancement, P1)

59 Branch
enhancement

Tracking

(geckoview62 wontfix, firefox-esr52 wontfix, firefox-esr60 wontfix, firefox61 wontfix, firefox62 wontfix, firefox63 wontfix, firefox64 fixed)

RESOLVED FIXED
mozilla64
Tracking Status
geckoview62 --- wontfix
firefox-esr52 --- wontfix
firefox-esr60 --- wontfix
firefox61 --- wontfix
firefox62 --- wontfix
firefox63 --- wontfix
firefox64 --- fixed

People

(Reporter: snorp, Assigned: snorp)

References

Details

(Whiteboard: [geckoview:klar:p2])

Attachments

(9 external files, 4 obsolete files)

If you do `new GeckoSession().open(GeckoRuntime.getDefault(...))`, this will cause us to leak a Gecko window. I think consumers will definitely expect that to be cleaned up by the finalizer. In conversations with :jchen, this is because the Parcelable implementation of GeckoSession allows the GeckoSession.Window to have shared ownership, and we don't want to close the window underneath someone else. Further, native code always holds a reference to the window, so it will never become garbage collected even if no other managed object holds a reference.
One idea to solve this would be to add a method that would return a wrapped `GeckoSession.Window` and close the session. The gist of it is: class SessionData implements Parcelable { private GeckoSession.Window window; public close() { ... } } class GeckoSession { ... SessionData forget() { SessionData data = new SessionData(mWindow); mWindow = null; return data; } } We'd then add a `GeckoSession` constructor that accepts a `SessionData` and basically does the same as `GeckoSession.transferFrom()` today. Naming is hard, so any suggestions there are welcome. This would ensure GeckoSession.Window is owned in only one place at a time, so a finalizer (either in GeckoSession or SessionData) can always close it.
(In reply to James Willcox (:snorp) (jwillcox@mozilla.com) from comment #1) > One idea to solve this would be to add a method that would return a wrapped > `GeckoSession.Window` and close the session. Whoops -- it does not close the session, simply transfers it
Another way to solve this would be to have a map of String -> WeakReference<GeckoSession>, where the strings are the result of GeckoSession.getId(). The parcelable impl in GeckoSession would then simply write the id into the bundle instead of the GeckoSession.Window instance as it does today. When (if) it's unparceled on the other side it can use the id to find the originating GeckoSession and use transferFrom() as we do today to move the GeckoSession.Window over. With this system the GeckoSession.Window is always owned by a single GeckoSession, so the owning GeckoSession can always close() in the finalizer. I like this much better than the solution in comment #1, but concede that having the map is bit of a kludge.
Hmm, except we're racing the GC now if the session goes out of scope. No good.
This change eliminates shared ownership of the window. It is always owned by a GeckoSession or the newly-introduced WindowHolder. This allows GeckoSession to close the window it holds in the the finalizer, if any, preventing leaks.
This also changes GeckoSession.transferFrom() to close any current window if one exists instead of throwing. This is possible now since the GeckoSession has exclusive ownership of the window (if it has one at all).
The attached patches are kind of a hybrid between comment #1 and #3. When GeckoSession is parceled, ownership of the GeckoSession.Window is transferred to a wrapper, WindowHolder, which is itself put into the parcel. When (if) inflated on the other side, the new GeckoSession takes ownership from WindowHolder. Both GeckoSession and WindowHolder implement finalize() to ensure the GeckoSession.Window cannot leak.
Assignee: nobody → snorp
This is necessary so that GeckoSession.Window can be garbage collected, at which point the finalizer will close the underlying nsWindow.
Attachment #9004416 - Attachment is obsolete: true
Attachment #9004417 - Attachment is obsolete: true
Comment on attachment 9005063 [details] Bug 1486596 - Implement finalizer for GeckoSession.Window r=jchen Jim Chen [:jchen] [:darchons] has approved the revision.
Attachment #9005063 - Flags: review+
Comment on attachment 9005064 [details] Bug 1486596 - Ensure GeckoSession.Window is owned by a single GeckoSession r=jchen Jim Chen [:jchen] [:darchons] has approved the revision.
Attachment #9005064 - Flags: review+
Comment on attachment 9004980 [details] Bug 1486596 - Add WeakRef support to mozilla::jni r=jchen Jim Chen [:jchen] [:darchons] has approved the revision.
Attachment #9004980 - Flags: review+
Comment on attachment 9004981 [details] Bug 1486596 - Make nsWindow hold a weak reference to GeckoSession.Window r=jchen Jim Chen [:jchen] [:darchons] has approved the revision.
Attachment #9004981 - Flags: review+
Priority: -- → P1
Whiteboard: [geckoview:klar:p2]
Jeff, does Focus explicitly close its GeckoSession? If it does, then this window leak won't affect Focus. Does Focus use a separate GeckoSession for each tab?
This will print a message each time a native JNI ref is added or removed from an object.
This is necessary because the GC root for GeckoEditable is a native reference, preventing the GC from recognizing that the only reference to the GeckoEditable is the owning GeckoSession and doing normal cycle collector stuff. We break the cycle ourselves by using a WeakReference to hold the GeckoSession within GeckoEditable.
This iterates the main loop until the specified WeakReference has been enqueued.
Comment on attachment 9006374 [details] Bug 1486596 - Hold a WeakReference to GeckoSession from GeckoEditable r=jchen Jim Chen [:jchen] [:darchons] has approved the revision.
Attachment #9006374 - Flags: review+
Emily says Focus closes GeckoSessions individually in Focus' cleanup method and then as a batch if the user closes all tabs. Focus releases the GeckoSession for each tab switching tabs and creates a new one for a new tab.
Flags: needinfo?(j)
Attachment #9006369 - Attachment is obsolete: true
Attachment #9006375 - Attachment is obsolete: true
Comment on attachment 9006374 [details] Bug 1486596 - Hold a WeakReference to GeckoSession from GeckoEditable r=jchen Jim Chen [:jchen] [:darchons] has requested changes to the revision.
Attachment #9006374 - Flags: review+
Comment on attachment 9006370 [details] Bug 1486596 - Hold a WeakRef to PanZoomController from nsWindow r=jchen Jim Chen [:jchen] [:darchons] has approved the revision.
Attachment #9006370 - Flags: review+
Comment on attachment 9006372 [details] Bug 1486596 - Hold a WeakRef to LayerSession::Compositor from nsWindow r=jchen Jim Chen [:jchen] [:darchons] has approved the revision.
Attachment #9006372 - Flags: review+
Comment on attachment 9006374 [details] Bug 1486596 - Hold a WeakReference to GeckoSession from GeckoEditable r=jchen Jim Chen [:jchen] [:darchons] has approved the revision.
Attachment #9006374 - Flags: review+
Comment on attachment 9006376 [details] Bug 1486596 - Add tests to ensure GeckoSession can be collected by the GC r=jchen Jim Chen [:jchen] [:darchons] has approved the revision.
Attachment #9006376 - Flags: review+
Pushed by jwillcox@mozilla.com: https://hg.mozilla.org/integration/mozilla-inbound/rev/fabcbe61060e Add WeakRef support to mozilla::jni r=jchen https://hg.mozilla.org/integration/mozilla-inbound/rev/e7ddac13c48f Hold a WeakRef to GeckoSession.Window from nsWindow r=jchen https://hg.mozilla.org/integration/mozilla-inbound/rev/4a8062e9732e Implement finalizer for GeckoSession.Window r=jchen https://hg.mozilla.org/integration/mozilla-inbound/rev/c0cef26afa24 Ensure GeckoSession.Window is owned by a single GeckoSession r=jchen https://hg.mozilla.org/integration/mozilla-inbound/rev/a82faa24a0a6 Hold a WeakRef to PanZoomController from nsWindow r=jchen https://hg.mozilla.org/integration/mozilla-inbound/rev/355f1c2a3f83 Hold a WeakRef to LayerSession::Compositor from nsWindow r=jchen https://hg.mozilla.org/integration/mozilla-inbound/rev/0ac1fbefa4f4 Hold a WeakReference to GeckoSession from GeckoEditable r=jchen https://hg.mozilla.org/integration/mozilla-inbound/rev/7e5bfc676ff7 Hold a WeakRef to EventDispatcher from native code r=jchen https://hg.mozilla.org/integration/mozilla-inbound/rev/c2b5dfcbd692 Add tests to ensure GeckoSession can be collected by the GC r=jchen
Product: Firefox for Android → GeckoView
Version: Firefox 59 → 59 Branch
Target Milestone: Firefox 64 → mozilla64
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: