[Jeremy, to Kevin Jacobs]
... Your suggestion seems to be that we should treat references from older generations to newer generations as external roots.
That's the way it works now: an object in gen N *is* an external root wrt any object it references in gen I with I < N.
So a cycle that spans generations will not get collected until everything is in the same generation.
Right, and that's what happens (already). When gen K is collected, all gens <= K are smushed into gen K at the start, and all trash cycles are collected except for those that contain at least one object in gen K+1 or higher.
Indeed, that does not seem harmful.
It hasn't been so far <wink>, although you can certainly construct cases where it causes an inconvenient delay in trash collection.
On the other hand, it's hard to reconcile an intuitive notion of generation with what we're doing by running GC over and over as you add more elements to your list. It doesn't seem right that your list becomes an "old" object just because a single function allocates 100k young objects. That is, I wish the notion of generations accommodated a baby boom in a generation.
I don't think you do. Pushing the parent object into an older generation is exactly what's supposed to save us from needing to scan all its children every time a gen0 collection occurs.
Under 2.2.1, Kevin's test case pushes "the list" into gen2 early on, and those of the list's children that existed at that time are never scanned again until another gen2 collection occurs. For a reason I still haven't determined, under current CVS "the whole list" is getting scanned by move_root_reachable() every time a gen0 collection occurs. It's also getting scanned by both subtract_refs() and move_root_reachable() every time a gen1 collection occurs. I'm not yet sure whether the mystery is why this happens in 2.3, or why it doesn't happen in 2.2.1 <0.5 wink>.