So I'm emitting some dynamic proxies via DefineDynamicAssembly
, and while testing I found that:
In my test I generate 10,000 types, and the one-type-per-assembly code runs about 8-10 times faster. The memory usage is completely in line with what I expected, but how come the time to generate the types is that much longer?
Edit: Added some sample code.
One assembly:
var an = new AssemblyName( "Foo" );
var ab = AppDomain.CurrentDomain.DefineDynamicAssembly( an, AssemblyBuilderAccess.Run );
var mb = ab.DefineDynamicModule( "Bar" );
for( int i = 0; i < 10000; i++ )
{
var tb = mb.DefineType( "Baz" + i.ToString( "000" ) );
var met = tb.DefineMethod( "Qux", MethodAttributes.Public );
met.SetReturnType( typeof( int ) );
var ilg = met.GetILGenerator();
ilg.Emit( OpCodes.Ldc_I4, 4711 );
ilg.Emit( OpCodes.Ret );
tb.CreateType();
}
One assembly per type:
for( int i = 0; i < 10000; i++ )
{
var an = new AssemblyName( "Foo" );
var ab = AppDomain.CurrentDomain.DefineDynamicAssembly( an,
AssemblyBuilderAccess.Run );
var mb = ab.DefineDynamicModule( "Bar" );
var tb = mb.DefineType( "Baz" + i.ToString( "000" ) );
var met = tb.DefineMethod( "Qux", MethodAttributes.Public );
met.SetReturnType( typeof( int ) );
var ilg = met.GetILGenerator();
ilg.Emit( OpCodes.Ldc_I4, 4711 );
ilg.Emit( OpCodes.Ret );
tb.CreateType();
}
Remarks. A dynamic assembly is an assembly that is created using the Reflection Emit APIs. You can use AssemblyBuilder to generate dynamic assemblies in memory and execute their code during the same application run.
Static assemblies are stored on disk in portable executable (PE) files. You can also use the . NET Framework to create dynamic assemblies, which are run directly from memory and are not saved to disk before execution. You can save dynamic assemblies to disk after they have executed.
Collectible assemblies are dynamic assemblies that can be unloaded without unloading the application domain in which they were created. All managed and unmanaged memory used by a collectible assembly and the types it contains can be reclaimed. Information such as the assembly name is removed from internal tables.
On my PC in LINQPad using C# 7.0 I get one assembly about 8.8 seconds, one assembly per type about 2.6 seconds. Most of the time in the one assembly is in DefineType
and CreateType
whereas in the time is mainly in DefineDynamicAssembly
+DefineDynamicModule
.
DefineType
checks there is no name conflicts, which is a Dictionary
lookup. If the Dictionary
is empty, this is about a check for null
.
The majority of the time is spent in CreateType
, but I don't see where, however it appears that it requires extra time adding types to a single Module.
Creating multiple modules slows the whole process down, but most of the time is spent creating modules and in DefineType
, which has to scan every module for a duplicate, so now has increasing up to 10,000 null
checks. With a unique module per type, CreateType
is very fast.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With