The default serialization for the dictionary should include type information for the type of dictionary used by the comparator and for the types of each element (both key and value), since they can be generally subtypes. These overheads must be added for each dictionary. If you print the data as a string, you can see that there are many fully qualified types, occupying many bytes:
\ 0 \ 0 \ 0 \ 0 ???? \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0? System.Collections.Generic.Dictionary 2[[System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]\0\0\0\aVersion\bComparer\bHashSize\rKeyValuePairs\0\0\b?System.Collections.Generic.GenericEqualityComparer 1 [[System.Int32, mscorlib, Version = 2.0.0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089]] \ b? System.Collections.Generic.KeyValuePair 2[[System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]][]\0\0\0\t\0\0\0\0\0\0\t\0\0\0\0\0\0?System.Collections.Generic.GenericEqualityComparer 1 [[ System.Int32, mscorlib, Version = 2.0.0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089]] \ 0 \ 0 \ 0 \ 0 \ a \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0? System.Collections.Generic.KeyValuePair 2[[System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]?????System.Collections.Generic.KeyValuePair 2 [[System.Int32, mscorlib, Version = 2.0.0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089], [System.Int32, mscorlib, Version = 2.0. 0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089]] \ 0 \ 0 \ 0keyvalue \ 0 \ 0 \ b \ b \ 0 \ 0 \ 0 \ 0 \ v
You might want to use a custom format for serialization, as well as a standard format that is a bit lighter, like JSON .