【转载】.Net中各种不同的对象创建方式的速度差异

本文原址:.Net中各种不同的对象创建方式的速度差异

 

本文章为本人个人博客相应文章的镜像:

原文地址: http://www.greatony.com/index.php/2010/02/06/speed-of-object-creation-in-dotnet/

 

 在.Net中,微软给我们提供了很多不同的创建对象实例的方法,它们的速度又各有不同,以下一一列举。

使用new关键字

这在.Net中是最常见,也是速度最快的方式:

1  var instance  =   new  Class();

 

 

使用System.Activator类的CreateInstance方法动态创建

这里的CreateInstance指的是Activator的非泛型方法:

1  var instance  =  System.Activator.CreateInstance( typeof (Class));

 

 

使用System.Activator类的CreateInstance<T>方法动态创建

这里的CreateInstance才是Activator的泛型方法:

 

1  var instance  =  System.Activator.CreateInstance < Class > ();

 

 

使用泛型约束,使用new关键字创建对象(泛型方法)

首先需要创建一个泛型的方法:

1  public   static  T CreateInstance < T > ()  where  T :  new ()
2  {
3       return   new  T();
4  }

 

 

这里利用泛型约束where T: new(),保证了T类型是可以用无参构造器构造的,所以代码里面就可以直接使用new T()来创建对象:

1  var instance  =  CreateInstance < Class > ();

 

 

使用泛型类的静态方法、泛型约束和new关键字创建

这里需要首先创建一个泛型类

1  public   static   class  StaticInitializer < T >   where  T: new ()
2  {
3       public   static  T CreateInstance()
4      {
5           return   new  T();
6      }
7  }

 

 

然后使用如下代码创建实例:

1  var instance  =  StaticInitializer < Class > .CreateInstance();

 

 

使用泛型类的动态方法、泛型约束和new关键字

这里使用的是泛型类的实力方法,需要首先创建一个泛型类:

1  public   class  DynamicInitializer < T >   where  T: new ()
2  {
3       public  T CreateInstance()
4      {
5           return   new  T();
6      }
7  }

 

 

使用的方法就是:

1  var initializer  =   new  DynamicInitializer < Class > ();
2  var instance  =  initializer.CreateInstance();

 

 

Ok,现在我一共提出了6种不同的创建对象的方式,大家可以猜猜这些创建对象的方式当中那个会比较快。

  1. 使用new关键字
  2. 使用System.Activator类的CreateInstance方法动态创建
  3. 使用System.Activator类的CreateInstance<T>方法动态创建
  4. 使用泛型约束,使用new关键字创建对象(泛型方法)
  5. 使用泛型类的静态方法、泛型约束和new关键字创建
  6. 使用泛型类的动态方法、泛型约束和new关键字

大家可以在评论里面给这些方法排个序,明天的文章我将会公布测试的结果

 

 

 

本文章为本人个人博客相应文章的镜像:

原文地址: http://www.greatony.com/index.php/2010/02/14/speed-of-object-creation-in-dotnet-ii/


OK,大家已经看到前面的文章了,本来说是第二天就发这篇文章的,但后来因为返回老家的原因,没有发成,特此补发。

测试环境:

  • Lenovo ThinkPad T61
  • CPU: Intel T7500
  • Mem: 2GB
  • Os: Windows Vista Ultimate (x86) sp1

测试内容:

创建100万个对象。

测试方式:


1  for (var i  =   0 ; i  <   1000000 ; i ++ )
2      //  create the instance


然后计算这段代码消耗的时间

测试结果:

  1. 使用new关键字   17ms
  2. 使用System.Activator类的CreateInstance方法动态创建    484ms
  3. 使用System.Activator类的CreateInstance<T>方法动态创建   1545ms
  4. 使用泛型约束,使用new关键字创建对象(泛型方法)1604ms
  5. 使用泛型类的静态方法、泛型约束和new关键字创建  1504ms
  6. 使用泛型类的动态方法、泛型约束和new关键字 1481ms

这里使用new关键字无疑是最快的,比较有趣的主要有以下2点:

  1. 使用System.Activator的非泛型方法比使用泛型方法快很多(超过200%)
  2. 使用泛型约束和new关键字创建的速度几乎和System.Activator的泛型方法的一样

那么,在下一篇文章里面,我将会探索和分析造成速度差异的原因,敬请期待。

 

 

 

 

本文章为本人个人博客相应文章的镜像:

 

原文地址: http://www.greatony.com/index.php/2010/02/14/speed-of-object-creation-in-dotnet-iii/ 

从前面的文章,我们发现以下两点有趣的东西:

  1. 使用System.Activator的非泛型方法比使用泛型方法快很多(超过200%)
  2. 使用泛型约束和new关键字创建的速度几乎和System.Activator的泛型方法的一样

 

在这篇文章里,我将会这两个问题做一个进一步的探究,我使用的工具就是鼎鼎大名的.Net反编译工具:Reflector,欢迎读者跟我一起探讨造成这个现象的原因。

第一段 从System.Activator.CreateInstance(Type)开始

我们先用Reflector打开.Net Framework 3.5中的mscorlib.dll,看看这里面,微软是怎么实现的。

首先看看System.Activator.CreateInstance(Type),它直接调用了System.Activator.CreateInstance(Type, Boolean),代码如下

1  public   static   object  CreateInstance(Type type)
2  {
3       return  CreateInstance(type,  false );
4  }

 

那么这个CreateInstance(Type, Boolean)的实现,是这样的:

 1  public   static   object  CreateInstance(Type type,  bool  nonPublic)
 2  {
 3       if  (type  ==   null )
 4      {
 5           throw   new  ArgumentNullException( " type " );
 6      }
 7      RuntimeType underlyingSystemType  =  type.UnderlyingSystemType  as  RuntimeType;
 8       if  (underlyingSystemType  ==   null )
 9      {
10           throw   new  ArgumentException(Environment.GetResourceString( " Arg_MustBeType " ),  " type " );
11      }
12       return  underlyingSystemType.CreateInstanceImpl( ! nonPublic);
13  }
14 

 

将这段代码简化一下,就是:

1  public   static   object  CreateInstance(Type type,  bool  nonPublic)
2  {
3      RuntimeType underlyingSystemType  =  type.UnderlyingSystemType  as  RuntimeType;
4       return  underlyingSystemType.CreateInstanceImpl( ! nonPublic);
5  }
6 

 

在RuntimeType的CreateInstanceImpl(bool isPublic)中,直接调用了CreateInstanceImpl(bool isPublic, bool skipVisibilityCheck, bool fillCache),这个函数的实现非常有意思,我先把代码贴出来:

 1  internal   object  CreateInstanceImpl( bool  publicOnly,  bool  skipVisibilityChecks,  bool  fillCache)
 2  {
 3      RuntimeTypeHandle typeHandle  =   this .TypeHandle;
 4      ActivatorCache cache  =  s_ActivatorCache;
 5       if  (cache  !=   null )
 6      {
 7          ActivatorCacheEntry entry  =  cache.GetEntry( this );
 8           if  (entry  !=   null )
 9          {
10               if  ((publicOnly  &&  (entry.m_ctor  !=   null ))  &&  ((entry.m_hCtorMethodHandle.GetAttributes()  &  MethodAttributes.MemberAccessMask)  !=  MethodAttributes.Public))
11              {
12                   throw   new  MissingMethodException(Environment.GetResourceString( " Arg_NoDefCTor " ));
13              }
14               object  obj2  =  typeHandle.Allocate();
15               if  (entry.m_ctor  !=   null )
16              {
17                   if  ( ! skipVisibilityChecks  &&  entry.m_bNeedSecurityCheck)
18                  {
19                      MethodBase.PerformSecurityCheck(obj2, entry.m_hCtorMethodHandle,  this .TypeHandle.Value,  0x10000000 );
20                  }
21                   try
22                  {
23                      entry.m_ctor(obj2);
24                  }
25                   catch  (Exception exception)
26                  {
27                       throw   new  TargetInvocationException(exception);
28                  }
29              }
30               return  obj2;
31          }
32      }
33       return   this .CreateInstanceSlow(publicOnly, fillCache);
34  }
35 

 

看起来非常复杂,其实他的实现也也就实现了一个缓存机制:

  1.     检查缓存中是否存在这个构造器的委托,如果有,就调用自己的typeHandler的Allocate()方法分配内存,然后调用构造器的委托初始化对象
  2.     如果没有缓存,就调用CreateInstanceSlow(bool isPublic, bool fillCache)创建对象,并填充缓存

 

好吧继续再看看这个CreateInstanceSlow里面干了什么事情。

照例先贴代码吧:

 1  private   object  CreateInstanceSlow( bool  publicOnly,  bool  fillCache)
 2  {
 3      RuntimeMethodHandle emptyHandle  =  RuntimeMethodHandle.EmptyHandle;
 4       bool  bNeedSecurityCheck  =   true ;
 5       bool  canBeCached  =   false ;
 6       bool  noCheck  =   false ;
 7       this .CreateInstanceCheckThis();
 8       if  ( ! fillCache)
 9      {
10          noCheck  =   true ;
11      }
12       object  obj2  =  RuntimeTypeHandle.CreateInstance( this , publicOnly, noCheck,  ref  canBeCached,  ref  emptyHandle,  ref  bNeedSecurityCheck);
13       if  (canBeCached  &&  fillCache)
14      {
15          ActivatorCache cache  =  s_ActivatorCache;
16           if  (cache  ==   null )
17          {
18              cache  =   new  ActivatorCache();
19              Thread.MemoryBarrier();
20              s_ActivatorCache  =  cache;
21          }
22          ActivatorCacheEntry ace  =   new  ActivatorCacheEntry( this , emptyHandle, bNeedSecurityCheck);
23          Thread.MemoryBarrier();
24          cache.SetEntry(ace);
25      }
26       return  obj2;
27  }
28 

 

这个函数写的很复杂,其实实现的东西很简单,其一是调用RuntimeTypeHandler.CreateInstance方法创建对象,然后再填充缓存,以加快下次创建对象的速度。

好了,我们现在已经非常接近事实的真相了。让我们从另外一个角度出发,看看CreateInstance<T>()干了什么事情。

第二段 从System.Activator.CreateInstance<T>()开始

这里,我们先看看他的实现:

1  public   static  T CreateInstance < T > ()
2  {
3       bool  bNeedSecurityCheck  =   true ;
4       bool  canBeCached  =   false ;
5      RuntimeMethodHandle emptyHandle  =  RuntimeMethodHandle.EmptyHandle;
6       return  (T) RuntimeTypeHandle.CreateInstance( typeof (T)  as  RuntimeType,  true true ref  canBeCached,  ref  emptyHandle,  ref  bNeedSecurityCheck);
7  }
8 

 

我们忽然就看到了我们熟悉的身影:RuntimeTypeHandler.CreateInstance方法,终于殊途同归啊。。。

也就是说,System.Activator.CreateInstance<T>()相当于调用了CreateInstanceSlow方法(但是没有缓存机制),这应该就是CreateInstance<T>比CreateInstance(Type)慢的主要原因,我们回顾一下这两个方法的时间消耗:

System.Activator.CreateInstance(Type):

  • 缓存机制时间消耗
  • RuntimeTypeHandler.Allocate()内存分配的时间消耗
  • 调用构造器委托初始化数据的时间消耗

 

这里不考虑缓存失败,调用CreateInstanceSlow的情况,因为这个只会发生一次。

System.Activator.CreateInstance(Type):

  • 调用RuntimeTypeHandler.CreateInstance的时间消耗

 

在下一篇文章中,我会对这两个函数的性能差异做进一步的分析

 

 

转载于:https://www.cnblogs.com/virusswb/articles/1672781.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值