I believe I have nailed down all of the edge and corner case behavior of the FinalizeQueue in this PR, but there is admittedly a lot, and it's not all covered by comments or documentation.
One thing not covered by the comments is what precisely happens when one FinalizeQueue is placed into another. If a later constructed FinalizeQueue is registered into an earlier one and otherwise lost, then the later queue will receive any about-to-be-freed objects, and then the earlier queue will also receive any duplicate registered objects (because the later queue is not yet black so none of its children are either). In the other case, where an earlier constructed FinalizeQueue is placed into a later one, then the later queue receives any soon-to-be-freed objects but the earlier one does not.
This seems inconsistent to me but any other behavior I can come up with is just as strange. In the later-in-earlier situation, if objects weren't placed into the earlier queue, then the earlier queue would miss freed objects if the later queue wasn't resurrected. In the earlier-in-later situation, if the earlier queue received objects and was resurrected then it would have received objects incorrectly.
This is the most consistent behavior I could come up with, and the algorithm that the collector is doing is simple.
Works a bit like https://docs.oracle.com/javase/8/docs/api/java/lang/ref/ReferenceQueue.html.
I believe I have nailed down all of the edge and corner case behavior of the
FinalizeQueue
in this PR, but there is admittedly a lot, and it's not all covered by comments or documentation.One thing not covered by the comments is what precisely happens when one
FinalizeQueue
is placed into another. If a later constructedFinalizeQueue
is registered into an earlier one and otherwise lost, then the later queue will receive any about-to-be-freed objects, and then the earlier queue will also receive any duplicate registered objects (because the later queue is not yet black so none of its children are either). In the other case, where an earlier constructedFinalizeQueue
is placed into a later one, then the later queue receives any soon-to-be-freed objects but the earlier one does not.This seems inconsistent to me but any other behavior I can come up with is just as strange. In the later-in-earlier situation, if objects weren't placed into the earlier queue, then the earlier queue would miss freed objects if the later queue wasn't resurrected. In the earlier-in-later situation, if the earlier queue received objects and was resurrected then it would have received objects incorrectly.
This is the most consistent behavior I could come up with, and the algorithm that the collector is doing is simple.