Created
April 14, 2016 21:14
-
-
Save kornman00/86b1701f228c0611501dd0cdb7d24d69 to your computer and use it in GitHub Desktop.
Avoiding heap allocations in generic serialization code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// #NOTE: be mindful of how large T actually is and whether or not your runtime does or doesn't | |
// optimize passing large structs by reference instead of copying bits to other parts of the stack | |
public static T Read<T>(this BinaryReader reader, T item = default(T)) | |
where T : IStreamSerializable, new() | |
{ | |
if (item == null) // value types are never null, so this helps us avoid heap allocations | |
item = new T(); | |
item.Load(reader); | |
return item; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.method public hidebysig static | |
!!T Read<.ctor (IStreamSerializable) T> ( | |
class [mscorlib]System.IO.BinaryReader reader, | |
[opt] !!T item | |
) cil managed | |
{ | |
.custom instance void [System.Core]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( | |
01 00 00 00 | |
) | |
// Method begins at RVA 0x1d9f0 | |
// Code size 64 (0x40) | |
.maxstack 5 | |
.locals init ( | |
[0] !!T | |
) | |
IL_0000: ldarg.1 | |
IL_0001: box !!T | |
IL_0006: brtrue IL_0030 | |
IL_000b: ldloca.s 0 | |
IL_000d: initobj !!T | |
IL_0013: ldloc.0 | |
IL_0014: box !!T | |
IL_0019: brfalse IL_0029 | |
IL_001e: ldloca.s 0 | |
IL_0020: initobj !!T | |
IL_0026: ldloc.0 | |
IL_0027: br.s IL_002e | |
IL_0029: call !!0 [mscorlib]System.Activator::CreateInstance<!!T>() | |
IL_002e: starg.s item | |
IL_0030: ldarga.s item | |
IL_0032: ldarg.0 | |
IL_0033: constrained. !!T | |
IL_0039: callvirt instance void IStreamSerializable::Load(class [mscorlib]System.IO.BinaryReader) | |
IL_003e: ldarg.1 | |
IL_003f: ret | |
} // end of method SerializationExtensions::Read |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public static T Read<T>(this BinaryReader reader, T item = null) where T : IStreamSerializable, new() | |
{ | |
if (item == null) | |
{ | |
item = ((default(T) == null) ? Activator.CreateInstance<T>() : default(T)); | |
} | |
item.Load(reader); | |
return item; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public static T Read<T>(this BinaryReader reader) | |
where T : IStreamSerializable, new() | |
{ | |
T item = new T(); // when T is a value type, this causes a heap allocation in Unity! | |
item.Load(reader); | |
return item; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
**** Type: MY_STRUCT // names have been changed to protect the innocent | |
Unique backtraces 22 | |
Avg Alloc 238.500000 | |
Avg Free 2.000000 | |
Avg Garbage 0.838574 | |
Frame Count 2 | |
Allocs 477 | |
Frees 4 | |
Skipped Alloc 0 | |
Skipped Free 0 | |
91 (%19.077568) // number of allocations from this specific backtrace | |
Sample address 000000002620D0F0 | |
(wrapper managed-to-native) object:__icall_wrapper_mono_object_new_specific | |
(wrapper managed-to-native) object:__icall_wrapper_mono_object_new_specific | |
SerializationExtensions:Read<MY_STRUCT> C:\[REDACTED]\Serialization.cs(330) | |
[REDACTED...] | |
(wrapper runtime-invoke) object:runtime_invoke_void__this__ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment