C# 可回收动态程序集中的静态字段访问缺乏性能
对于动态二进制翻译模拟器,我需要生成具有访问静态字段的类的可收集的.NET程序集。但是,当在可回收程序集中使用静态字段时,执行性能比不可回收程序集低2-3倍。这一现象在中国并不存在 不使用静态字段的可回收程序集 在下面的代码中,抽象类C# 可回收动态程序集中的静态字段访问缺乏性能,c#,.net,clr,C#,.net,Clr,对于动态二进制翻译模拟器,我需要生成具有访问静态字段的类的可收集的.NET程序集。但是,当在可回收程序集中使用静态字段时,执行性能比不可回收程序集低2-3倍。这一现象在中国并不存在 不使用静态字段的可回收程序集 在下面的代码中,抽象类absrtest的方法MyMethod由可回收和不可回收的动态程序集实现。使用CreateTypeConst时,MyMethod将ulong参数值乘以两个常量值,而使用CreateTypeField时,第二个因子取自 构造函数初始化了静态字段MyField 为了获得
absrtest
的方法MyMethod
由可回收和不可回收的动态程序集实现。使用CreateTypeConst
时,MyMethod
将ulong参数值乘以两个常量值,而使用CreateTypeField时,第二个因子取自
构造函数初始化了静态字段MyField
为了获得真实的结果,将MyMethod
结果累积到for循环中
以下是测量结果(.NET CLR 4.5/4.6):
Testing non-collectible const multiply:
Elapsed: 8721.2867 ms
Testing collectible const multiply:
Elapsed: 8696.8124 ms
Testing non-collectible field multiply:
Elapsed: 10151.6921 ms
Testing collectible field multiply:
Elapsed: 33404.4878 ms
using System;
using System.Reflection;
using System.Reflection.Emit;
using System.Diagnostics;
public abstract class AbstrTest {
public abstract ulong MyMethod(ulong x);
}
public class DerivedClassBuilder {
private static Type CreateTypeConst(string name, bool collect) {
// Create an assembly.
AssemblyName myAssemblyName = new AssemblyName();
myAssemblyName.Name = name;
AssemblyBuilder myAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(
myAssemblyName, collect ? AssemblyBuilderAccess.RunAndCollect : AssemblyBuilderAccess.Run);
// Create a dynamic module in Dynamic Assembly.
ModuleBuilder myModuleBuilder = myAssembly.DefineDynamicModule(name);
// Define a public class named "MyClass" in the assembly.
TypeBuilder myTypeBuilder = myModuleBuilder.DefineType("MyClass", TypeAttributes.Public, typeof(AbstrTest));
// Create the MyMethod method.
MethodBuilder myMethodBuilder = myTypeBuilder.DefineMethod("MyMethod",
MethodAttributes.Public | MethodAttributes.ReuseSlot | MethodAttributes.Virtual | MethodAttributes.HideBySig,
typeof(ulong), new Type [] { typeof(ulong) });
ILGenerator methodIL = myMethodBuilder.GetILGenerator();
methodIL.Emit(OpCodes.Ldarg_1);
methodIL.Emit(OpCodes.Ldc_I4_2);
methodIL.Emit(OpCodes.Conv_U8);
methodIL.Emit(OpCodes.Mul);
methodIL.Emit(OpCodes.Ret);
return myTypeBuilder.CreateType();
}
private static Type CreateTypeField(string name, bool collect) {
// Create an assembly.
AssemblyName myAssemblyName = new AssemblyName();
myAssemblyName.Name = name;
AssemblyBuilder myAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(
myAssemblyName, collect ? AssemblyBuilderAccess.RunAndCollect : AssemblyBuilderAccess.Run);
// Create a dynamic module in Dynamic Assembly.
ModuleBuilder myModuleBuilder = myAssembly.DefineDynamicModule(name);
// Define a public class named "MyClass" in the assembly.
TypeBuilder myTypeBuilder = myModuleBuilder.DefineType("MyClass", TypeAttributes.Public, typeof(AbstrTest));
// Define a private String field named "MyField" in the type.
FieldBuilder myFieldBuilder = myTypeBuilder.DefineField("MyField",
typeof(ulong), FieldAttributes.Private | FieldAttributes.Static);
// Create the constructor.
ConstructorBuilder constructor = myTypeBuilder.DefineConstructor(
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName | MethodAttributes.HideBySig,
CallingConventions.Standard, Type.EmptyTypes);
ConstructorInfo superConstructor = typeof(AbstrTest).GetConstructor(
BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance,
null, Type.EmptyTypes, null);
ILGenerator constructorIL = constructor.GetILGenerator();
constructorIL.Emit(OpCodes.Ldarg_0);
constructorIL.Emit(OpCodes.Call, superConstructor);
constructorIL.Emit(OpCodes.Ldc_I4_2);
constructorIL.Emit(OpCodes.Conv_U8);
constructorIL.Emit(OpCodes.Stsfld, myFieldBuilder);
constructorIL.Emit(OpCodes.Ret);
// Create the MyMethod method.
MethodBuilder myMethodBuilder = myTypeBuilder.DefineMethod("MyMethod",
MethodAttributes.Public | MethodAttributes.ReuseSlot | MethodAttributes.Virtual | MethodAttributes.HideBySig,
typeof(ulong), new Type [] { typeof(ulong) });
ILGenerator methodIL = myMethodBuilder.GetILGenerator();
methodIL.Emit(OpCodes.Ldarg_1);
methodIL.Emit(OpCodes.Ldsfld, myFieldBuilder);
methodIL.Emit(OpCodes.Mul);
methodIL.Emit(OpCodes.Ret);
return myTypeBuilder.CreateType();
}
public static void Main() {
ulong accu;
Stopwatch stopwatch;
try {
Console.WriteLine("Testing non-collectible const multiply:");
AbstrTest i0 = (AbstrTest)Activator.CreateInstance(
CreateTypeConst("MyClassModule0", false));
stopwatch = Stopwatch.StartNew();
accu = 0;
for (uint i = 0; i < 0xffffffff; i++)
accu += i0.MyMethod(i);
stopwatch.Stop();
Console.WriteLine("Elapsed: " + stopwatch.Elapsed.TotalMilliseconds + " ms");
Console.WriteLine("Testing collectible const multiply:");
AbstrTest i1 = (AbstrTest)Activator.CreateInstance(
CreateTypeConst("MyClassModule1", true));
stopwatch = Stopwatch.StartNew();
accu = 0;
for (uint i = 0; i < 0xffffffff; i++)
accu += i1.MyMethod(i);
stopwatch.Stop();
Console.WriteLine("Elapsed: " + stopwatch.Elapsed.TotalMilliseconds + " ms");
Console.WriteLine("Testing non-collectible field multiply:");
AbstrTest i2 = (AbstrTest)Activator.CreateInstance(
CreateTypeField("MyClassModule2", false));
stopwatch = Stopwatch.StartNew();
accu = 0;
for (uint i = 0; i < 0xffffffff; i++)
accu += i2.MyMethod(i);
stopwatch.Stop();
Console.WriteLine("Elapsed: " + stopwatch.Elapsed.TotalMilliseconds + " ms");
Console.WriteLine("Testing collectible field multiply:");
AbstrTest i3 = (AbstrTest)Activator.CreateInstance(
CreateTypeField("MyClassModule3", true));
stopwatch = Stopwatch.StartNew();
accu = 0;
for (uint i = 0; i < 0xffffffff; i++)
accu += i3.MyMethod(i);
stopwatch.Stop();
Console.WriteLine("Elapsed: " + stopwatch.Elapsed.TotalMilliseconds + " ms");
}
catch (Exception e) {
Console.WriteLine("Exception Caught " + e.Message);
}
}
}
这是我的复制机代码:
Testing non-collectible const multiply:
Elapsed: 8721.2867 ms
Testing collectible const multiply:
Elapsed: 8696.8124 ms
Testing non-collectible field multiply:
Elapsed: 10151.6921 ms
Testing collectible field multiply:
Elapsed: 33404.4878 ms
using System;
using System.Reflection;
using System.Reflection.Emit;
using System.Diagnostics;
public abstract class AbstrTest {
public abstract ulong MyMethod(ulong x);
}
public class DerivedClassBuilder {
private static Type CreateTypeConst(string name, bool collect) {
// Create an assembly.
AssemblyName myAssemblyName = new AssemblyName();
myAssemblyName.Name = name;
AssemblyBuilder myAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(
myAssemblyName, collect ? AssemblyBuilderAccess.RunAndCollect : AssemblyBuilderAccess.Run);
// Create a dynamic module in Dynamic Assembly.
ModuleBuilder myModuleBuilder = myAssembly.DefineDynamicModule(name);
// Define a public class named "MyClass" in the assembly.
TypeBuilder myTypeBuilder = myModuleBuilder.DefineType("MyClass", TypeAttributes.Public, typeof(AbstrTest));
// Create the MyMethod method.
MethodBuilder myMethodBuilder = myTypeBuilder.DefineMethod("MyMethod",
MethodAttributes.Public | MethodAttributes.ReuseSlot | MethodAttributes.Virtual | MethodAttributes.HideBySig,
typeof(ulong), new Type [] { typeof(ulong) });
ILGenerator methodIL = myMethodBuilder.GetILGenerator();
methodIL.Emit(OpCodes.Ldarg_1);
methodIL.Emit(OpCodes.Ldc_I4_2);
methodIL.Emit(OpCodes.Conv_U8);
methodIL.Emit(OpCodes.Mul);
methodIL.Emit(OpCodes.Ret);
return myTypeBuilder.CreateType();
}
private static Type CreateTypeField(string name, bool collect) {
// Create an assembly.
AssemblyName myAssemblyName = new AssemblyName();
myAssemblyName.Name = name;
AssemblyBuilder myAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(
myAssemblyName, collect ? AssemblyBuilderAccess.RunAndCollect : AssemblyBuilderAccess.Run);
// Create a dynamic module in Dynamic Assembly.
ModuleBuilder myModuleBuilder = myAssembly.DefineDynamicModule(name);
// Define a public class named "MyClass" in the assembly.
TypeBuilder myTypeBuilder = myModuleBuilder.DefineType("MyClass", TypeAttributes.Public, typeof(AbstrTest));
// Define a private String field named "MyField" in the type.
FieldBuilder myFieldBuilder = myTypeBuilder.DefineField("MyField",
typeof(ulong), FieldAttributes.Private | FieldAttributes.Static);
// Create the constructor.
ConstructorBuilder constructor = myTypeBuilder.DefineConstructor(
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName | MethodAttributes.HideBySig,
CallingConventions.Standard, Type.EmptyTypes);
ConstructorInfo superConstructor = typeof(AbstrTest).GetConstructor(
BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance,
null, Type.EmptyTypes, null);
ILGenerator constructorIL = constructor.GetILGenerator();
constructorIL.Emit(OpCodes.Ldarg_0);
constructorIL.Emit(OpCodes.Call, superConstructor);
constructorIL.Emit(OpCodes.Ldc_I4_2);
constructorIL.Emit(OpCodes.Conv_U8);
constructorIL.Emit(OpCodes.Stsfld, myFieldBuilder);
constructorIL.Emit(OpCodes.Ret);
// Create the MyMethod method.
MethodBuilder myMethodBuilder = myTypeBuilder.DefineMethod("MyMethod",
MethodAttributes.Public | MethodAttributes.ReuseSlot | MethodAttributes.Virtual | MethodAttributes.HideBySig,
typeof(ulong), new Type [] { typeof(ulong) });
ILGenerator methodIL = myMethodBuilder.GetILGenerator();
methodIL.Emit(OpCodes.Ldarg_1);
methodIL.Emit(OpCodes.Ldsfld, myFieldBuilder);
methodIL.Emit(OpCodes.Mul);
methodIL.Emit(OpCodes.Ret);
return myTypeBuilder.CreateType();
}
public static void Main() {
ulong accu;
Stopwatch stopwatch;
try {
Console.WriteLine("Testing non-collectible const multiply:");
AbstrTest i0 = (AbstrTest)Activator.CreateInstance(
CreateTypeConst("MyClassModule0", false));
stopwatch = Stopwatch.StartNew();
accu = 0;
for (uint i = 0; i < 0xffffffff; i++)
accu += i0.MyMethod(i);
stopwatch.Stop();
Console.WriteLine("Elapsed: " + stopwatch.Elapsed.TotalMilliseconds + " ms");
Console.WriteLine("Testing collectible const multiply:");
AbstrTest i1 = (AbstrTest)Activator.CreateInstance(
CreateTypeConst("MyClassModule1", true));
stopwatch = Stopwatch.StartNew();
accu = 0;
for (uint i = 0; i < 0xffffffff; i++)
accu += i1.MyMethod(i);
stopwatch.Stop();
Console.WriteLine("Elapsed: " + stopwatch.Elapsed.TotalMilliseconds + " ms");
Console.WriteLine("Testing non-collectible field multiply:");
AbstrTest i2 = (AbstrTest)Activator.CreateInstance(
CreateTypeField("MyClassModule2", false));
stopwatch = Stopwatch.StartNew();
accu = 0;
for (uint i = 0; i < 0xffffffff; i++)
accu += i2.MyMethod(i);
stopwatch.Stop();
Console.WriteLine("Elapsed: " + stopwatch.Elapsed.TotalMilliseconds + " ms");
Console.WriteLine("Testing collectible field multiply:");
AbstrTest i3 = (AbstrTest)Activator.CreateInstance(
CreateTypeField("MyClassModule3", true));
stopwatch = Stopwatch.StartNew();
accu = 0;
for (uint i = 0; i < 0xffffffff; i++)
accu += i3.MyMethod(i);
stopwatch.Stop();
Console.WriteLine("Elapsed: " + stopwatch.Elapsed.TotalMilliseconds + " ms");
}
catch (Exception e) {
Console.WriteLine("Exception Caught " + e.Message);
}
}
}
使用系统;
运用系统反思;
使用System.Reflection.Emit;
使用系统诊断;
公共抽象类AbstrTest{
公开摘要ulong MyMethod(ulong x);
}
公共类派生类生成器{
私有静态类型CreateTypeConst(字符串名,bool collect){
//创建一个程序集。
AssemblyName myAssemblyName=新的AssemblyName();
myAssemblyName.Name=名称;
AssemblyBuilder myAssembly=AppDomain.CurrentDomain.DefinedDynamicAssembly(
myAssemblyName,collect?AssemblyBuilderAccess.Run和collect:AssemblyBuilderAccess.Run);
//在动态部件中创建动态模块。
ModuleBuilder myModuleBuilder=myAssembly.DefinedDynamicModule(名称);
//在程序集中定义一个名为“MyClass”的公共类。
TypeBuilder myTypeBuilder=myModuleBuilder.DefineType(“MyClass”,TypeAttributes.Public,typeof(AbstrTest));
//创建MyMethod方法。
MethodBuilder myMethodBuilder=myTypeBuilder.DefineMethod(“MyMethod”,
MethodAttributes.Public | MethodAttributes.ReuseSlot | MethodAttributes.Virtual | MethodAttributes.hidebysing,
typeof(ulong),新类型[]{typeof(ulong)};
ILGenerator methodIL=myMethodBuilder.GetILGenerator();
发射方法(操作码Ldarg_1);
发射方法(操作码Ldc_I4_2);
方法发射(操作码转换U8);
发射方法(操作码Mul);
发射方法(操作码Ret);
返回myTypeBuilder.CreateType();
}
私有静态类型CreateTypeField(字符串名称,bool collect){
//创建一个程序集。
AssemblyName myAssemblyName=新的AssemblyName();
myAssemblyName.Name=名称;
AssemblyBuilder myAssembly=AppDomain.CurrentDomain.DefinedDynamicAssembly(
myAssemblyName,collect?AssemblyBuilderAccess.Run和collect:AssemblyBuilderAccess.Run);
//在动态部件中创建动态模块。
ModuleBuilder myModuleBuilder=myAssembly.DefinedDynamicModule(名称);
//在程序集中定义一个名为“MyClass”的公共类。
TypeBuilder myTypeBuilder=myModuleBuilder.DefineType(“MyClass”,TypeAttributes.Public,typeof(AbstrTest));
//在类型中定义名为“MyField”的私有字符串字段。
FieldBuilder myFieldBuilder=myTypeBuilder.DefineField(“MyField”,
typeof(ulong),FieldAttributes.Private | FieldAttributes.Static);
//创建构造函数。
ConstructorBuilder constructor=myTypeBuilder.DefineConstructor(
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName | MethodAttributes.HideBySig,
调用约定。标准,类型。空类型);
ConstructorInfo superConstructor=typeof(AbstrTest).GetConstructor(
BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance,
null,Type.EmptyTypes,null);
ILGenerator constructorIL=constructor.GetILGenerator();
构造函数发出(操作码Ldarg_0);
constructorIL.Emit(操作码.Call,超级构造函数);
构造发射(操作码Ldc_I4_2);
构造发射(操作码转换U8);
constructorIL.Emit(操作码.Stsfld,myFieldBuilder);
构造释放(操作码释放);
//创建MyMethod方法。
MethodBuilder myMethodBuilder=myTypeBuilder.DefineMethod(“MyMethod”,
MethodAttributes.Public | MethodAttributes.ReuseSlot | MethodAttributes.Virtual | MethodAttributes.hidebysing,
typeof(ulong),新类型[]{typeof(ulong)};
ILGenerator methodIL=myMethodBuilder.GetILGenerator();
发射方法(操作码Ldarg_1);
methodIL.Emit(opcode.Ldsfld,myFieldBuilder);
发射方法(操作码Mul);
发射方法(操作码Ret);
返回myTypeBuilder.CreateType();
}
公共静态void Main(){
乌龙accu;
秒表;
试一试{
控制台.WriteLine(“测试不可收集常数乘法:”);
AbstrTest i0=(AbstrTest)Activator.CreateInstance(
CreateTypeConst(“MyClassModule0”,false));
stopwatch=stopwatch.StartNew();
accu=0;
对于(uint i=0;i<0xffffffff;i++)
accu+=i0.MyMethod(i);
秒表;
Console.WriteLine(“运行时间:+stopwatch.appeased.totalmillizes+“ms”);
控制台.WriteLine(“测试可收集常数乘:”);
AbstrTest i1=(AbstrTest)Activator.CreateInstance(
CreateTypeConst(“MyClassModule1”,true));
stopwatch=stopwatch.StartNew();
accu=0;
对于(uint i=0;i<0xffffffff;i++)
accu+=i1.MyMethod(i);
秒表;
Console.WriteLine(“运行时间:+stopwatch.appeased.totalmillizes+“ms”);
Console.WriteLine(“测试不可收集字段乘法:”);
AbstrTest i2=(AbstrTest)Activator.CreateInstance(
CreateTypeField(“MyClassModule2”,false));
stopwatch=stopwatch.StartNew();
accu=0;
对于(uint i=0;i<0xffffffff;i++)
accu+=i2.MyMethod(i);
秒表;
骗局
059F0480 push dword ptr [ebp+0Ch] ; Ldarg_1, high 32-bits
059F0483 push dword ptr [ebp+8] ; Ldarg_1, low 32-bits
059F0486 mov ecx,59FC8A0h ; arg2 = DynamicClassDomainId
059F048B xor edx,edx ; arg1 = DomainId
059F048D call JIT_GetSharedNonGCStaticBaseDynamicClass (73E0A6C7h)
059F0492 push dword ptr [eax+8] ; @myFieldBuilder, high 32-bits
059F0495 push dword ptr [eax+4] ; @myFieldBuilder, low 32-bits
059F0498 call @JIT_LMul@16 (73AE1C20h) ; 64-bit multiply