Use pre-boxed objects for common attribute values#40
Conversation
…heap allocation Reduce List and Linq allocations during parsing Remove obsolete Odds and Evens methods
There was a problem hiding this comment.
Pull request overview
This PR focuses on reducing allocations during vector tile parsing by pre-sizing collections and reusing pre-boxed objects for common attribute values, while also removing the previously used odd/even tag-splitting helpers.
Changes:
- Pre-size parsed layer/feature collections to reduce
List<T>growth allocations. - Replace LINQ-based tag splitting with a single indexed loop and introduce pre-boxed objects for common attribute values (notably
bool). - Remove the obsolete
GetOdds/GetEvensextension methods and their associated tests.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| tests/IEnumerableExtensionTests.cs | Removes tests for the deleted GetOdds/GetEvens extension methods. |
| src/VectorTileParser.cs | Preallocates layer list and feature list capacity based on proto counts. |
| src/ExtensionMethods/IEnumerableExtensions.cs | Removes the obsolete public GetOdds/GetEvens LINQ helpers. |
| src/AttributesParser.cs | Eliminates LINQ allocations, parses tags via indexed loop, and uses pre-boxed objects for common values. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
can you add a benchmark.net test that proves this new method is better? |
|
It appears that I can't. The library doesn't seem to detect boxing as a memory allocation, and your current sample data doesn't contain any boolean values anyway. What I can do is use a tile from my data source and then take screenshots of the Visual Studio heap diagnostics window. (Protobuf has its own boxed boolean too, so there are three in total.) |
|
should be possible to create a vector tile with booleans (in the benchmark setup) and let the benchmark test read it, see what benchmark reports about the heap/stack allocations. |
|
This is what I did. It reports that 96 bytes were allocated both times, even though we can see hundreds of boxed booleans. |
|
ah ok, when inspecting the heap diagnostics window, does it run in release mode (as is needed for benchmark test)? Maybe some optimalization is going on. |
|
You can see the exact same allocations in both release and debug builds. |
|
Ping! |
|
I did a quick test with a benchmark test (n=1) result: current:
before:
So allocated memory is improved from 1.4 MB to 703 KB, also mean parsing time is 3 times faster. Can you add such a test and recheck results? Benchmark code I've used: |
|
I added the test you posted, but I increased the number of attributes to 100,000 because the results included a warning that the test completed too quickly.
|
|
thanks it's in release 5.3.1 |


After a short amount of scrolling around my map, without these changes I see over 200,000 boxed booleans in the heap. The allocation count continues to climb as new tiles are parsed.
With these changes, there are exactly two boxed boolean allocations: one for
trueand one forfalse. The boxed numeric values (0 and 1) are helpful too, but it's bool which provides the biggest win.