On Mon Apr 24 16:11:02 2023 +0000, Jacek Caban wrote:
Somehow it doesn't end up cleaning them later.
It would be interesting to understand why. Note that a long-living application may never release any document and we still want CC to do its job properly.
Well it's pretty obvious why, in hindsight of course (wasn't when I started).
The Cycle Collector runs periodically, using some internal heuristics. But it runs only on the main thread, and only sometimes during processing of events (it can be starved as well, if it takes too long).
It can also be forced to run, of course, which is what we're doing when we're closing the document object. That won't work when some gecko event keeps ref to it, since it will be a hard ref "unknown edge".
Additionally, it runs during "shutdown"—with a deep scan to clean everything. The CC is global, so this shutdown is for the entire gecko engine. But in our use case, shutdown *never* happens. We never tell it to shutdown, and I don't see a way to tell it either (no XPCOM API to shutdown XPCOM itself).
But that's besides the point because even if we had such an API we couldn't make use of it during document object release. Since we aren't really shutting down the engine, another doc obj can be created later, and it would be bad if the CC was shutdown.
So for tests it's pretty clear to see what happens:
Objects leak. Some events hold ref to the objects. The CC is forced to run when the doc obj is released, but since there's those refs it doesn't know of, they're kept alive and skipped.
There's no further message pump at the end of the test (unless we run another test which creates another document obj). So the objects simply leak. Of course in this particular case it's benign for memory usage, since we're shutting down the test process anyway.
But it does mean they show up as leaks when we try to look for them, since they were never freed.
This isn't just for the events holding refs, the SnowWhiteKiller for instance doesn't run immediately, it runs on the next CC (SnowWhite are objects marked for deletion but which aren't deleted immediately, for whatever reason I can't understand). If the last forced CC has some SnowWhite objects, they will leak when the test process finishes.
If an app somehow does this and doesn't pump messages to gecko anymore (not sure if that's possible?) those objects will leak. Since both the CC and the events holding refs are only "executed" during the gecko message pump / event loop.
That's why I wanted to clean them up during the forced CC since it's the only way I could find to ensure it… But you're right that it can potentially have issues with multiple doc objects.
I can probably drop these patches for now, but the leaks will exist when analyzed, sadly (even the CC graph will show "unknown edge"). Probably not a problem in practice as much, since it's only the "last" few document objects that will be leaking, but still annoying.
If you have any ideas how to do this please let me know as I'd love to have these integrated upstream, if possible.
Otherwise I guess I will keep these patches for local use when I analyze leaks since otherwise it becomes impossible to analyze them. Sigh.