craftworkgames / MonoGame.Extended

Extensions to make MonoGame more awesome
http://www.monogameextended.net/
Other
1.44k stars 325 forks source link

Fix Bag<T> allocation during foreach iteration #814

Closed LilithSilver closed 1 year ago

LilithSilver commented 1 year ago

The documentation of Entities recommends iteration through a Bag<int> of entities with foreach. However, due to Bag<T> not providing a duck-typed enumerator for foreach, this causes memory allocation. If a system processes a large number of entities (let's say 100k, which is reasonable for an ECS framework) this will cause 100k BagEnumerator allocations per frame (!) due to the boxing conversion when the internal BagEnumerator is converted to IEnumerator.

More information about this problem can be found here: https://nede.dev/blog/preventing-unnecessary-allocation-in-net-collections

This PR fixes this by simply adding a duck-typed GetEnumerator() method, and making BagEnumerator public. It also adds a unit test to prevent future issues while using foreach.

Gandifil commented 1 year ago

Thanks for your attention, this is a very interesting article. I have checked this anomaly in benchmark, and saw worst results: the duck-typed version is 5 times more effective.