.Net Framework 4.0 - Opcodes.Box 出现在带有 int 键的字典中
.Net Framework 4.0 - Opcodes.Box present in Dictionary with int key
我正在尝试调查带有枚举键的字典是否仍然在较新版本的 .Net 中生成垃圾(例如 >= 4)
请在此处查看 Shawn Hargreaves 博客 post,详细了解为什么我什至为此烦恼...
(http://blogs.msdn.com/b/shawnhar/archive/2007/07/02/twin-paths-to-garbage-collector-nirvana.aspx)
我知道非常具体,但 xbox 上的垃圾是/可能是一个非常真正的问题。
我创建了一个小的 .Net v4 控制台应用程序来比较为 Dictionary 和 Dicationary 生成的 IL,并注意到两组代码中的 'box' 操作码让我很困惑。
.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 a value type (of the type specified in valTypeToken) to a true
object reference.
这里的框不是堆分配吗?如果不是,那么我如何判断何时存在可能导致 Xbox 出现问题的堆分配?(通过查看 IL)它是否取决于其他一些上下文?
内存分析器(例如 CLR Profiler)是否是确定的唯一方法?
是的,它是一个盒子,但在这种情况下它不重要 - 至少,对于 regular .NET 来说不是;这是一张 != null
支票; JIT 知道如何识别这些值类型,并且可以删除 从机器代码中检查。
据说。
要确定,您需要查看 post-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
"object" 没有分配。请注意,如果我将代码更改为
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>
是使用安全。
我正在尝试调查带有枚举键的字典是否仍然在较新版本的 .Net 中生成垃圾(例如 >= 4)
请在此处查看 Shawn Hargreaves 博客 post,详细了解为什么我什至为此烦恼... (http://blogs.msdn.com/b/shawnhar/archive/2007/07/02/twin-paths-to-garbage-collector-nirvana.aspx) 我知道非常具体,但 xbox 上的垃圾是/可能是一个非常真正的问题。
我创建了一个小的 .Net v4 控制台应用程序来比较为 Dictionary 和 Dicationary 生成的 IL,并注意到两组代码中的 'box' 操作码让我很困惑。
.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 a value type (of the type specified in valTypeToken) to a true object reference.
这里的框不是堆分配吗?如果不是,那么我如何判断何时存在可能导致 Xbox 出现问题的堆分配?(通过查看 IL)它是否取决于其他一些上下文? 内存分析器(例如 CLR Profiler)是否是确定的唯一方法?
是的,它是一个盒子,但在这种情况下它不重要 - 至少,对于 regular .NET 来说不是;这是一张 != null
支票; JIT 知道如何识别这些值类型,并且可以删除 从机器代码中检查。
据说。
要确定,您需要查看 post-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
"object" 没有分配。请注意,如果我将代码更改为
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>
是使用安全。