.Net Framework 4.0 - Opcodes.Box is present in the dictionary with the int key

I am trying to investigate whether garbage enumeration keys dictionaries continue in newer versions of .Net (say> = 4)

See Sean Hargreaves's blog blog here for details on why I'm even worried about this ... ( http://blogs.msdn.com/b/shawnhar/archive/2007/07/02/twin-paths-to- garbage-collector-nirvana.aspx ) Very specific, I know, but garbage on xbox is / can be a very serious problem.

I created a small .Net v4 console application comparing IL generated for Dictionary and Dicationary, and noticed the “box” opcode in both sets of code that really confused me.

.method private hidebysig instance int32 FindEntry ( !TKey key ) cil managed { // Method begins at RVA 0x61030 // Code size 138 (0x8a) .maxstack 3 .locals init ( [0] int32, [1] int32 ) IL_0000: ldarg.1 IL_0001: box !TKey <----Hmmmm! IL_0006: brtrue.s IL_000e IL_0008: ldc.i4.5 IL_0009: call void System.ThrowHelper::ThrowArgumentNullException(valuetype System.ExceptionArgument) IL_000e: ldarg.0 IL_000f: ldfld int32[] class System.Collections.Generic.Dictionary`2<!TKey, !TValue>::buckets IL_0014: brfalse.s IL_0088 

https://msdn.microsoft.com/en-us/library/system.reflection.emit.opcodes.box%28v=vs.110%29.aspx

Convert the type of the value (of the type specified in valTypeToken) to true; an object reference.

Is the field here not a heap distribution? If not, how can I find out when there are heap allocations that can cause Xbox? (From a look at IL). Does it depend on some other context? Could there be a memory profiler (e.g. CLR Profiler) the only way to tell for sure?

+6
source share
2 answers

Yes, this is a field, but in this case it should not matter - at least not for normal .NET; this is a check != null ; JIT knows how to recognize them for value types, and can remove which are checked from machine code.

Allegedly.

To be sure, you need to look at the post-JIT machine code, not IL.

It will also be important which JIT you use, which makes the job difficult.

In the worst case scenario: you can use the CoreCLR code to collapse your dictionary of values.

+5
source

I will say that the problem is resolved. I took the code from http://beardseye.blogspot.it/2007/08/nuts-enum-conundrum.html

 enum TestEnum { e10, e9, e8, e7, e6, e5, e4, e3, e2, e1 } class Program { static void Main(string[] args) { Dictionary<TestEnum, int> dict = new Dictionary<TestEnum, int>(); for (int l = 0; l < 100000; l++) { TestEnum x = (TestEnum)(l % 10); dict[x] = 100000 - (int)x; } for (TestEnum x = TestEnum.e10; x <= TestEnum.e1; x++) { Console.WriteLine(dict[x]); } } } 

And I ran it with the Visual Studio 2013 profiler. There are no TestEnum objects. "Note that if I changed the code to

 dict[x] = 100000 - x.GetHashCode(); 

then I get a lot of TestEnum distributions.

Another test:

 public class TestEnumComparer : IEqualityComparer<TestEnum> { public bool Equals(TestEnum x, TestEnum y) { return x == y; } public int GetHashCode(TestEnum obj) { return obj.GetHashCode(); } } 

and

 Dictionary<TestEnum, int> dict = new Dictionary<TestEnum, int>(new TestEnumComparer()); 

However, I get many TestEnum distributions.

So, I will say that EqualityComparer<T>.Default does something to not list the boxes.

If you look at the source of EqualityComparer in the CreateComparer() method:

 // If T is an int-based Enum, return an EnumEqualityComparer<T> // See the METHOD__JIT_HELPERS__UNSAFE_ENUM_CAST and METHOD__JIT_HELPERS__UNSAFE_ENUM_CAST_LONG cases in getILIntrinsicImplementation if (t.IsEnum && Enum.GetUnderlyingType(t) == typeof(int)) { return (EqualityComparer<T>)RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(EnumEqualityComparer<int>), t); } 

there is some special code for comparing int enum and only them.

And I can confirm that if I change enum to

 enum TestEnum : long 

then the distributions caused by boxing appear !:-)

So at the end

 Dictionary<enum_that_is_an_int, Foo> 

safe

any other type of enum not !:-)

Note that this is true for .NET> = 4.0. I looked at CreateComparer() mscorlib 2.0.0.0, and there is no such check, so on the .NET 2.0-3.5 Dictionary<enum_that_is_an_int, Foo> not safe to use.

+3
source

Source: https://habr.com/ru/post/986803/


All Articles