.Net中各种不同的对象创建方式的速度差异三

  • 来源: www.knowsky.com 作者: sevenleaf   2010-04-22/17:09
  •       从前面的文章,我们发现以下两点有趣的东西:

          使用System.Activator的非泛型方法比使用泛型方法快很多(超过200%)
          使用泛型约束和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 }
          将这段代码简化一下,就是:

    1 public static object CreateInstance(Type type, bool nonPublic)
    2 {
    3     RuntimeType underlyingSystemType = type.UnderlyingSystemType as RuntimeType;
    4     return underlyingSystemType.CreateInstanceImpl(!nonPublic);
    5 }
          在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 }
          看起来非常复杂,其实他的实现也也就实现了一个缓存机制:

          检查缓存中是否存在这个构造器的委托,如果有,就调用自己的typeHandler的Allocate()方法分配内存,然后调用构造器的委托初始化对象
          如果没有缓存,就调用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 }
          这个函数写的很复杂,其实实现的东西很简单,其一是调用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 }
          我们忽然就看到了我们熟悉的身影:RuntimeTypeHandler.CreateInstance方法,终于殊途同归啊。。。

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

          System.Activator.CreateInstance(Type):

          缓存机制时间消耗
          RuntimeTypeHandler.Allocate()内存分配的时间消耗
          调用构造器委托初始化数据的时间消耗
          这里不考虑缓存失败,调用CreateInstanceSlow的情况,因为这个只会发生一次。

          System.Activator.CreateInstance(Type):

          调用RuntimeTypeHandler.CreateInstance的时间消耗。


    评论 {{userinfo.comments}}

    {{money}}

    {{question.question}}

    A {{question.A}}
    B {{question.B}}
    C {{question.C}}
    D {{question.D}}
    提交

    驱动号 更多