從前面的文章,我們發(fā)現(xiàn)以下兩點有趣的東西:
1、使用System.Activator的非泛型方法比使用泛型方法快很多(超過200%)
2、使用泛型約束和new關鍵字創(chuàng)建的速度幾乎和System.Activator的泛型方法的一樣
在這篇文章里,我將會這兩個問題做一個進一步的探究,我使用的工具就是鼎鼎大名的.Net反編譯工具:Reflector,歡迎讀者跟我一起探討造成這個現(xiàn)象的原因。
第一段 從System.Activator.CreateInstance(Type)開始
我們先用Reflector打開.Net Framework 3.5中的mscorlib.dll,看看這里面,微軟是怎么實現(xiàn)的。
首先看看System.Activator.CreateInstance(Type),它直接調(diào)用了System.Activator.CreateInstance(Type, Boolean),代碼如下
1 public static object CreateInstance(Type type)
2 {
3 return CreateInstance(type, false);
4 }
那么這個CreateInstance(Type, Boolean)的實現(xiàn),是這樣的:
01 public static object CreateInstance(Type type, bool nonPublic)
02 {
03 if (type == null)
04 {
05 throw new ArgumentNullException("type");
06 }
07 RuntimeType underlyingSystemType = type.UnderlyingSystemType as RuntimeType;
08 if (underlyingSystemType == null)
09 {
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)中,直接調(diào)用了CreateInstanceImpl(bool isPublic, bool skipVisibilityCheck, bool fillCache),這個函數(shù)的實現(xiàn)非常有意思,我先把代碼貼出來:
01 internal object CreateInstanceImpl(bool publicOnly, bool skipVisibilityChecks, bool fillCache)
02 {
03 RuntimeTypeHandle typeHandle = this.TypeHandle;
04 ActivatorCache cache = s_ActivatorCache;
05 if (cache != null)
06 {
07 ActivatorCacheEntry entry = cache.GetEntry(this);
08 if (entry != null)
09 {
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 }
看起來非常復雜,其實他的實現(xiàn)也也就實現(xiàn)了一個緩存機制:
檢查緩存中是否存在這個構(gòu)造器的委托,如果有,就調(diào)用自己的typeHandler的Allocate()方法分配內(nèi)存,然后調(diào)用構(gòu)造器的委托初始化對象
如果沒有緩存,就調(diào)用CreateInstanceSlow(bool isPublic, bool fillCache)創(chuàng)建對象,并填充緩存
好吧繼續(xù)再看看這個CreateInstanceSlow里面干了什么事情。
照例先貼代碼吧:
01 private object CreateInstanceSlow(bool publicOnly, bool fillCache)
02 {
03 RuntimeMethodHandle emptyHandle = RuntimeMethodHandle.EmptyHandle;
04 bool bNeedSecurityCheck = true;
05 bool canBeCached = false;
06 bool noCheck = false;
07 this.CreateInstanceCheckThis();
08 if (!fillCache)
09 {
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 }
這個函數(shù)寫的很復雜,其實實現(xiàn)的東西很簡單,其一是調(diào)用RuntimeTypeHandler.CreateInstance方法創(chuàng)建對象,然后再填充緩存,以加快下次創(chuàng)建對象的速度。
好了,我們現(xiàn)在已經(jīng)非常接近事實的真相了。讓我們從另外一個角度出發(fā),看看CreateInstance()干了什么事情。
第二段 從System.Activator.CreateInstance()開始
這里,我們先看看他的實現(xiàn):
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()相當于調(diào)用了CreateInstanceSlow方法(但是沒有緩存機制),這應該就是CreateInstance比CreateInstance(Type)慢的主要原因,我們回顧一下這兩個方法的時間消耗:
System.Activator.CreateInstance(Type):
緩存機制時間消耗
RuntimeTypeHandler.Allocate()內(nèi)存分配的時間消耗
調(diào)用構(gòu)造器委托初始化數(shù)據(jù)的時間消耗
這里不考慮緩存失敗,調(diào)用CreateInstanceSlow的情況,因為這個只會發(fā)生一次。
System.Activator.CreateInstance(Type):
調(diào)用RuntimeTypeHandler.CreateInstance的時間消耗
在下一篇文章中,我會對這兩個函數(shù)的性能差異做進一步的分析