.NET Framework 4.0 -OpCodes.box在字典中带有int键



我正在尝试调查带有枚举键的字典是否仍会在.net(say> = 4)

的较新版本中生成垃圾

请参阅此处的Shawn Hargreaves博客文章,以获取有关我什至为此感到烦恼的详细信息...(http://blogs.msdn.com/b/shawnhar/archive/2007/07/02/twin-paths-to-garbage-collector-nirvana.aspx)我知道很具体,但是Xbox上的垃圾是/可能是一个非常问题。

我创建了一些.NET V4控制台应用程序,比较了为字典和dicationary生成的IL,并在两组代码中都注意到了一个"框" opcode,这确实使我感到困惑。

.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(v=vs.110).aspx

将价值类型(在Valtypetkoken中指定的类型)转换为true 对象参考。

这里的盒子不是堆分配吗?如果不是,那么我该如何判断何时可能会导致Xbox挣扎的堆?(从查看IL)这是否取决于其他情况?内存分析器(例如,CLR Profiler)是否是确定的唯一方法?

是的,它是一个盒子,但是在这种情况下,不应该没关系 - 至少不是常规 .net;这是!= null检查;JIT知道如何识别这些值类型,并且可以从机器代码中检查可以删除。

据称。

可以肯定的是,您需要查看列车后的机器代码,而不是IL。

您使用的是哪种jit,这使它变得更难。

最坏的情况:您可以使用coreclr代码来滚动自己的价值式字典。

我会说解决了问题。我从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]);
        }
    }
}

我已经与Visual Studio 2013的探索器一起运行。TestEnum"对象"没有分配。请注意,如果我将代码更改为

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

然后我得到了许多TestEnum的分配。

其他测试:

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

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

我仍然得到许多TestEnum分配。

所以我要说的是EqualityComparer<T>.Default做一些不插入枚举的事情。

如果您在EqualityComparer源中查看CreateComparer()方法:

// 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);
}

有一些特殊的代码可以比较 int enum,只有它们。

,我可以确认如果将enum更改为

enum TestEnum : long

然后出现由拳击引起的分配!: - )

所以,最后

Dictionary<enum_that_is_an_int, Foo>

安全使用,

不是其他类型的enum!: - )

请注意,对于.net> = 4.0是正确的。我已经查看了 mscorlib 2.0.0.0 CreateComparer(),没有这样的检查,因此.NET 2.0-3.5 Dictionary<enum_that_is_an_int, Foo>不能安全使用。

最新更新