WEB开发网
开发学院WEB开发ASP .Net中各种不同的对象创建方式的速度差异(三) 阅读

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

 2010-02-25 10:45:56 来源:WEB开发网   
核心提示:本文章为本人个人博客相应文章的镜像:原文地址: http://www.greatony.com/index.php/2010/02/20/speed-of-object-creation-in-dotnet-iii/ 从前面的文章,我们发现以下两点有趣的东西: 使用System.Activator的非泛型方法比使用泛
本文章为本人个人博客相应文章的镜像:

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



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



使用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 }
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


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



  检查缓存中是否存在这个构造器的委托,如果有,就调用自己的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 }
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的时间消耗

Tags:Net 各种 不同

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接