Lifespan of a Collidable Pair?
Posted: Tue Nov 06, 2012 4:36 pm
Hi Norbo,
I've been doing some experimenting with reducing garbage generation of CollidablePairs. My app has near zero garbage generation, but there is still a little bit that happens as a result of CollidablePair objects. While they are structs, as you know they contain the two Collidable references which in turn make the struct generate some garbage.
I've been able to make some changes that avoid the garbage, but it has one flaw which I have as yet been unable to find a solution for. With my changes, Collidable objects track a index into an array of Collidables. This handle is used by the CollidablePair, removing the only reference types in the CollidablePair and in turn eliminating the garbage. Because the array is fixed in size, Collidables need to register and deregister from this array so the index/handle may be reused.
My early attempts at this involved Colliders permanently reserving their handle and adding a Dispose method to release it. This triggered a cascade of changes related to making a bunch of stuff in Bepu disposable for the sole purpose of ensuring Colliders were disposed properly. This was a lot of work, overhead and complexity that came with increased risk of defects so I eventually abandoned it despite eventually getting it to work. Another option I considered is a finalizer on the Collidable to release the index, but when the game generates no garbage, no finalizers get called and the index pool is eventually exhausted. I could trigger a GC when this occurs to recover the unused handles, but that would defeat the purpose. One possible option is to track a list of WeakReferences to the Colliders and release their index/id when a routine update would check and discover they are unreferenced. I don't really like that idea either, a bit too much management overhead for my taste when I think there is a better solution...
Recently, it crossed my mind that all I really need is for Colliders to be registered when there is at least one CollidablePair that needs to track it. So I modified my handle tracker to have an AddIdRef()/ReleaseIdRef() which were called at what I had hoped would bound the time where a CollidablePair needed to have access to the Collidable objects. So long as all CollidablePair objects correctly added/released references to the Collider, it seems this should make it possible for the Collider to reserve an index on the first AddIdRef (putting the reference to the collider in the array in the process) and release the index (and clear the corresponding reference) on the ReleaseIdRef where the refcounter reached zero.
This all sounds well and good, but my efforts at finding the proper spots to put AddIdRef/ReleaseIdRef have failed, and this mismatch means that it just doesn't work. Yet. I have tried a couple of spots, but I seem to be overlooking something and I've been unable to get the add/release to work as intended. I'd really like to figure this out because it is one of the few remaining sources of garbage generation in my game and while it might not seem like much it definitely adds up and contributes to triggering periodic GC which I would like to elimininate.
I've attached the modified files and a support class in case you want to check it out. The new code is wrapped with #if COLLIDER_HANDLES which I turn on at a project level when working on this.
(Edit: removed it since all this seems to not be necessary based on Norbo's response)
My last attempt has the AddIdRef occurring in GroupPairHandler.TryToAdd, and the ReleaseIdRef in GroupPairHandler.UpdateContacts just before the CollidablePairHandler toReturn is returned to it's Factory. If you have a chance to check this out sometime I would really appreciate it. I am hopeful you will just know where to put the calls to AddIdRef/ReleaseIdRef and it will work once they are in the right place, but perhaps there is some other reason why this can't work. I just don't know; I don't know the internals of Bepu well enough yet to be certain either way. It would be really great to find the answer to this, regardless.
Thanks again for everything Bepu!
I've been doing some experimenting with reducing garbage generation of CollidablePairs. My app has near zero garbage generation, but there is still a little bit that happens as a result of CollidablePair objects. While they are structs, as you know they contain the two Collidable references which in turn make the struct generate some garbage.
I've been able to make some changes that avoid the garbage, but it has one flaw which I have as yet been unable to find a solution for. With my changes, Collidable objects track a index into an array of Collidables. This handle is used by the CollidablePair, removing the only reference types in the CollidablePair and in turn eliminating the garbage. Because the array is fixed in size, Collidables need to register and deregister from this array so the index/handle may be reused.
My early attempts at this involved Colliders permanently reserving their handle and adding a Dispose method to release it. This triggered a cascade of changes related to making a bunch of stuff in Bepu disposable for the sole purpose of ensuring Colliders were disposed properly. This was a lot of work, overhead and complexity that came with increased risk of defects so I eventually abandoned it despite eventually getting it to work. Another option I considered is a finalizer on the Collidable to release the index, but when the game generates no garbage, no finalizers get called and the index pool is eventually exhausted. I could trigger a GC when this occurs to recover the unused handles, but that would defeat the purpose. One possible option is to track a list of WeakReferences to the Colliders and release their index/id when a routine update would check and discover they are unreferenced. I don't really like that idea either, a bit too much management overhead for my taste when I think there is a better solution...
Recently, it crossed my mind that all I really need is for Colliders to be registered when there is at least one CollidablePair that needs to track it. So I modified my handle tracker to have an AddIdRef()/ReleaseIdRef() which were called at what I had hoped would bound the time where a CollidablePair needed to have access to the Collidable objects. So long as all CollidablePair objects correctly added/released references to the Collider, it seems this should make it possible for the Collider to reserve an index on the first AddIdRef (putting the reference to the collider in the array in the process) and release the index (and clear the corresponding reference) on the ReleaseIdRef where the refcounter reached zero.
This all sounds well and good, but my efforts at finding the proper spots to put AddIdRef/ReleaseIdRef have failed, and this mismatch means that it just doesn't work. Yet. I have tried a couple of spots, but I seem to be overlooking something and I've been unable to get the add/release to work as intended. I'd really like to figure this out because it is one of the few remaining sources of garbage generation in my game and while it might not seem like much it definitely adds up and contributes to triggering periodic GC which I would like to elimininate.
I've attached the modified files and a support class in case you want to check it out. The new code is wrapped with #if COLLIDER_HANDLES which I turn on at a project level when working on this.
(Edit: removed it since all this seems to not be necessary based on Norbo's response)
My last attempt has the AddIdRef occurring in GroupPairHandler.TryToAdd, and the ReleaseIdRef in GroupPairHandler.UpdateContacts just before the CollidablePairHandler toReturn is returned to it's Factory. If you have a chance to check this out sometime I would really appreciate it. I am hopeful you will just know where to put the calls to AddIdRef/ReleaseIdRef and it will work once they are in the right place, but perhaps there is some other reason why this can't work. I just don't know; I don't know the internals of Bepu well enough yet to be certain either way. It would be really great to find the answer to this, regardless.
Thanks again for everything Bepu!