On Mon Jul 17 11:40:25 2023 +0000, Jacek Caban wrote:
This extra complication to GC does not seem needed for me. As I mentioned earlier, if you track weak references, you could just use the existing traversal mechanism. To summarize: "zombie" objects are not great in the first place, the solution depends on GC to a degree that it doesn't need to, delays reclaiming memory even in simple cases and it makes GC more complicated than it needs to be. I'd expect that avoiding all this would make the code simpler.
For reference, I also took a brief look at how wine-gecko handles weak
maps, and it seems to be pretty similar (in concept), so I think it's enough. Aside from weak refs, as a side note, some (most?) of JS engine depend much more on GC for object handling than we do. They often don't track object ref count at all, so objects can't be freed any other way than by GC. In such implementations, essentially all unused objects are "zombies". This is not how our jscript works (while changing that may be theoretically possible, it does not really align with how jscript exposes its internals with IDispatch). We pay the price of tracking ref count, but benefit from the fact that we can reclaim memory immediately in simple cases, allowing GC to run less often and on smaller graphs.
Do you mean just the "free_dead_weak_refs" part? That's the only thing I could conceivably get rid of by getting rid of the zombie objects, but I did it this way because it's actually better in terms of performance, and not much worse in terms of memory.
Tracking weak refs will add some memory overhead as well, while zombies only exist for those refs that are released until the next GC, but they don't keep any refs so they don't add any complications to the graph or extend lives of other objects at all.
Here's the problem though. The other new part of the GC, traversing weak maps, has nothing to do with zombies. While it's true that I could traverse the weak map entry values as part of the key's traversal if we had weak ref tracking, it does *not* work in all cases (it will have some leaks). This was my original idea, but it does not handle the cases where the WeakMap itself is "dead", since it will still traverse them in such case from the key, even though they're not accessible (because you need **both** the WeakMap *and* the key to access it, not just the key).
I can't just check the WeakMap's liveness, though, because it could change *during* the traversal and become alive. In such case, we would end up unlinking a live object, which is even worse than a leak.
It does with this current method as well which is why I have to keep re-iterating over the weak maps until no more changes are done.
So, are you sure it's worth it? Do you have some ideas to tackle this problem?