Hello World
Spiga

老赵谈IL(2):CLR内部有太多太多IL看不到的东西,包括您平时必须了解的那些

2009-06-03 14:34 by 老赵, 29680 visits

我一直建议大家不要倾向于学习IL的原因有二:

  1. IL能够说明的内容太少,包括大部分.NET“必知必会”。
  2. IL能够获得的信息从高级语言中也大都可以知道。

而这篇文章便是希望通过实例来把第1点解释清楚,而第2点则留给下一篇文章来解释。

在文章开始之前,我先要承认两个错误:

  • 首先,上一篇文章对于“IL”和“汇编”的阐述还有些混淆。在这方面某些朋友给出了一些更确切地说法,IL是一种为.NET平台设计的汇编语言,拥有大量.NET平台中特有的高级特性。而x86汇编等则是与机器码一一对应的文字形式代码。不过为了方便表述,在这一系列文章中,还是以“IL”来指代.NET平台上的中间语言,以“汇编”来指代x86汇编这种和特定CPU平台紧密相关的事物——包括之前那篇文章,其实是在阐述IL和汇编之间的关系和区别,以及该如何对待它们的问题,而并非为IL是否可以被叫做是“汇编”进行争论。
  • 其次,在第1篇文章发布的时候,现在这篇文章,也就是本系列第2篇的标题是“汇编可以看到太多IL看不到的东西”。不过后来在半夜重读这篇文章,并且仔细整理这篇文章的示例时发现出了一个问题——我并不是在讲汇编,要探索CLR中的各种问题也并不是仅仅靠汇编来发现的。当时写文章的时候谈了太多的IL和汇编,最终把自己的思路也给绕了进去。现已修改,希望没有给朋友们造成误解,抱歉。今后我也会尽量避免此类情况发生。

好了,现在开始继续我们这次的话题。

既然是讨论IL,自然要讨论IL可以做什么,这样才能够以此得出IL究竟该不该学,如果该学的话有应该怎么学——这话当然是对你,我,他个人来说的,不可一概而论。不过也有一个东西需要了解的,就是IL到底表达出了什么,IL又没有表达出什么东西。

在这里继续强调一下上文的结论:无论IL是否算是一种“汇编”,都不影响它是一种非常高级的编程语言,拥有各种高级特性,例如泛型、引用类型,值类型,方法属性等等,这些特性才是我们判断的依据,而不是它是否能够被冠上“汇编”的“称号”。简单地说,我们应该看它“能(或不能)做什么”,而不是它“能(或不能)被叫做什么”。以下就通过几个示例来展示一些情况:

示例一:探究泛型在某些情况下的性能问题

为了契合本文的内容,也为了说明问题,我先举一个例子,那正是在《从汇编入手,探究泛型的性能问题》一文中使用过的例子:

namespace TestConsole
{
    public class MyArrayList
    {
        public MyArrayList(int length)
        {
            this.m_items = new object[length];
        }

        private object[] m_items;

        public object this[int index]
        {
            [MethodImpl(MethodImplOptions.NoInlining)]
            get
            {
                return this.m_items[index];
            }
            [MethodImpl(MethodImplOptions.NoInlining)]
            set
            {
                this.m_items[index] = value;
            }
        }
    }

    public class MyList<T>
    {
        public MyList(int length)
        {
            this.m_items = new T[length];
        }

        private T[] m_items;

        public T this[int index]
        {
            [MethodImpl(MethodImplOptions.NoInlining)]
            get
            {
                return this.m_items[index];
            }
            [MethodImpl(MethodImplOptions.NoInlining)]
            set
            {
                this.m_items[index] = value;
            }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            MyArrayList arrayList = new MyArrayList(1);
            arrayList[0] = arrayList[0] ?? new object();

            MyList<object> list = new MyList<object>(1);
            list[0] = list[0] ?? new object();

            Console.WriteLine("Here comes the testing code.");

            var a = arrayList[0];
            var b = list[0];

            Console.ReadLine();
        }
    }
}

那篇文章的目的是证明“.NET中,就算在使用Object作为泛型类型的时候,也不会比直接使用Object类型性能差”。于是我准备了两个类,一个是MyList泛型容器,一个是MyArrayList直接使用Object类型的容器。在Main方法中将对MyList<Object>和MyArrayList的下标索引进行访问。至此,便出现了一些疑问,为泛型容器使用Object类型,是否比直接使用Object类型性能要差?于是乎,我们来看MyArrayList.get_Item和MyList<T>.get_Item两个方法的IL代码——没错,就是它们的下标get操作:

// MyArrayList的get_Item方法
.method public hidebysig specialname instance object get_Item(int32 index) cil managed noinlining
{
    .maxstack 8
    L_0000: ldarg.0 
    L_0001: ldfld object[] TestConsole.MyArrayList::m_items
    L_0006: ldarg.1 
    L_0007: ldelem.ref 
    L_0008: ret 
}

// MyList<T>的get_Item方法
.method public hidebysig specialname instance !T get_Item(int32 index) cil managed noinlining
{
    .maxstack 8
    L_0000: ldarg.0 
    L_0001: ldfld !0[] TestConsole.MyList`1::m_items
    L_0006: ldarg.1 
    L_0007: ldelem.any !T
    L_000c: ret 
}

朋友们一定已经发现了,这两个方法的区别只在于红色的两句。嗯,我们就“默认”ldfld指令的功能在两段代码中产生的效果完全相同(毕竟是相同的指令嘛),但是您觉得ldelem.ref指令和ldelem.any两条指令的效果如何,它们是一样的吗?我们通过查阅一些资料可以了解到说,ldelem.any的作用是加载一个泛型向量或数组中的元素。不过它的性能如何?您能得出结果说,它就和ldelem.ref指令一样吗?

我想,除非您了解到JIT对待这两个指令的具体方式,否则您是无法得出其中性能高低的。因为IL还是过于高级,您看到了一条IL指令,您可以知道它的作用,但是您还是不知道它最终造成了何种结果。您还是无法证明“Object泛型集合的性能不会低于直接存放Object的非泛型集合”。也正因为如此,我在那篇文章里探究问题的手段,是比较了MyArrayList.get_Item方法和MyList<Object>.get_Item方法的汇编代码,最后得出结果是“毫无二致”。由于汇编代码和机器代码一一对应,因此观察汇编代码就可以完全了解CPU是如何执行这两个方法的。汇编代码一模一样,就意味着CPU对待这两个方法的方式一模一样,它们的性能怎么会有不同呢?

于是,您过去,现在或将来,可能就会在某本书、某篇博客或文章看到这样一种说法:.NET的Object泛型容器的性能不会低于直接使用Object的容器,因为CLR在处理Object泛型的时候,会生成与直接使用Object类型时一模一样的类型,因此性能是不会降低的。但是您是通过学习IL可以了解这些吗?我认为,如果您只是学习了IL,最终还是要“听别人说”才能知道这些,而即使您不学IL,在“听别人说”了之后您也了解了这些——同时也不会因为不了解IL而变得“易忘”等等。

同样道理,IL的call指令和callvirt指令的区别是什么呢?“别人会告诉你”call指令直接就去调用了那个方法,而callvirt还需要去虚方法表里去“寻找”那个真正的方法;“别人可能还会告诉你”,查找虚方法是靠方法表地址加偏移量;《Essential .NET》还会将方法表的实现结构告诉给你,而这些都是IL不会告诉您的。您就算了解再多IL,也不如“别人告诉你”的这些来得重要。您要了解“别人告诉你”的东西,也不需要了解多少IL。

示例二:只有经过调用的方法才能获得其汇编代码吗?

许多资料都告诉我们,在一个方法被第一次调用之前,它是不会被JIT的。也就是说,直到第一次调用时它才会被转化为机器码。不过,这个真是这样吗?我们还是准备一段简单的C#代码:

namespace TestConsole
{
    class Program
    {
        [MethodImpl(MethodImplOptions.NoInlining)]
        private static void SomeMethod()
        {
            Console.WriteLine("Hello World!");
        }

        static void Main(string[] args)
        {
            Console.WriteLine("Before JITed.");
            Console.ReadLine();

            SomeMethod();

            Console.WriteLine("After JITed");
            Console.ReadLine();
        }
    }
}

那么Main方法的IL代码是怎么样的呢?

.method private hidebysig static void Main(string[] args) cil managed
{
    .entrypoint
    .maxstack 8
    // 分配字符串"Before JITed"
    L_0000: ldstr "Before JITed."
    // 调用Console.WriteLine方法
    L_0005: call void [mscorlib]System.Console::WriteLine(string)
    // 调用Console.ReadLine方法
    L_000a: call string [mscorlib]System.Console::ReadLine()
    L_000f: pop 
    // 调用Program.SomeMethod方法
    L_0010: call void TestConsole.Program::SomeMethod()
    // 分配字符串"After JITed"
    L_0015: ldstr "After JITed"
    // 调用Console.WriteLine方法
    L_001a: call void [mscorlib]System.Console::WriteLine(string)
    // 调用Console.ReadLine方法
    L_001f: call string [mscorlib]System.Console::ReadLine()
    L_0024: pop 
    L_0025: ret 
}

IL代码多容易懂呀,这段IL代码基本上就和我们的C#一样。没错,这就是IL的作用。IL和C#一样,都是用于表现程序逻辑。C#使用if...else、while、for等等丰富语法,而在IL中就会变成判断+跳转语句。但是,您从一段几十行的IL语句中,看出一句十几行的while逻辑——收获在哪里?除此之外,C#分配一个变量,IL也分配一个。C#调用一个方法,IL就call或callvirt一下。C#里new一个,IL中就newobj一下(自然也会有一些特殊,例如可以使用jmp或tail call一个方法——是为尾递归,但也只是及其特殊的情况)。可以发现IL的功能大部分就是C#可以表现的功能。而C#隐藏掉的一些细节,在IL这里同样没有显示出来!

那么我们又该如何发现一些细节呢?例如“书本”告诉我们的JIT的工作方式:方法第一次调用之后才会生成机器码。

这段程序会打印三行文字,在打印出Before JITed和After JITed字样之后都会有一次停止,需要用户按回车之后才能继续。在进行试验的时候,您可以在程序暂停的时候使用WinDbg的File - Attach to Process命令附加到TestConsole.exe进程中,或者在两次暂停时各生成一个dump文件,这样便可不断地重现一些过程。否则的话,应用程序两次启动所生成的地址很可能会完全不同——因为JIT的工作是动态的,有时候很难提前把握。

好,我们已经进入了第一个Console.ReadLine暂停,在点击回车继续下去之前。我们先使用WinDbg进行调试。以下是Main方法的汇编代码:

0:000> !name2ee *!TestConsole.Program
Module: 70f61000 (mscorlib.dll)
--------------------------------------
Module: 00172c5c (TestConsole.exe)
Token: 0x02000002
MethodTable: 00173010
EEClass: 001712d0
Name: TestConsole.Program
0:000> !dumpmt -md 00173010
EEClass: 001712d0
Module: 00172c5c
Name: TestConsole.Program
mdToken: 02000002  (...\bin\Release\TestConsole.exe)
BaseSize: 0xc
ComponentSize: 0x0
Number of IFaces in IFaceMap: 0
Slots in VTable: 7
--------------------------------------
MethodDesc Table
   Entry MethodDesc      JIT Name
71126ab0   70fa4944   PreJIT System.Object.ToString()
71126ad0   70fa494c   PreJIT System.Object.Equals(System.Object)
71126b40   70fa497c   PreJIT System.Object.GetHashCode()
71197540   70fa49a0   PreJIT System.Object.Finalize()
0017c019   00173008     NONE TestConsole.Program..ctor()
0017c011   00172ff0     NONE TestConsole.Program.SomeMethod()
003e0070   00172ffc      JIT TestConsole.Program.Main(System.String[])
0:000> !u 003e0070
Normal JIT generated code
TestConsole.Program.Main(System.String[])
Begin 003e0070, size 4d
>>> 003e0070 55              push    ebp
003e0071 8bec            mov     ebp,esp
*** WARNING: Unable to verify checksum for mscorlib.ni.dll
003e0073 e8a8d3da70      call    mscorlib_ni+0x22d420 (7118d420) (System.Console.get_Out(), ...)
003e0078 8bc8            mov     ecx,eax
003e007a 8b153020d102    mov     edx,dword ptr ds:[2D12030h] ("Before JITed.")
003e0080 8b01            mov     eax,dword ptr [ecx]
003e0082 ff90d8000000    call    dword ptr [eax+0D8h]
003e0088 e8971b2571      call    mscorlib_ni+0x6d1c24 (71631c24) (System.Console.get_In(), ...)
003e008d 8bc8            mov     ecx,eax
003e008f 8b01            mov     eax,dword ptr [ecx]
003e0091 ff5064          call    dword ptr [eax+64h]
003e0094 ff15f82f1700    call    dword ptr ds:[172FF8h] (TestConsole.Program.SomeMethod(), ...)
003e009a e881d3da70      call    mscorlib_ni+0x22d420 (7118d420) (System.Console.get_Out(), ...)
003e009f 8bc8            mov     ecx,eax
003e00a1 8b153420d102    mov     edx,dword ptr ds:[2D12034h] ("After JITed")
003e00a7 8b01            mov     eax,dword ptr [ecx]
003e00a9 ff90d8000000    call    dword ptr [eax+0D8h]
003e00af e8701b2571      call    mscorlib_ni+0x6d1c24 (71631c24) (System.Console.get_In(), ...)
003e00b4 8bc8            mov     ecx,eax
003e00b6 8b01            mov     eax,dword ptr [ecx]
003e00b8 ff5064          call    dword ptr [eax+64h]
003e00bb 5d              pop     ebp
003e00bc c3              ret

请关注上面那个被标红的call语句,它的含义是:

  1. 先从读取172FF8地址中的值,这才是方法调用的目标地址(即SomeMethod方法)。
  2. 使用call指令调用刚才读取到的目标地址

那么在第一次调用SomeMethod方法之前,目标地址的指令是什么呢?

0:000> dd 172FF8
00172ff8  0017c011 71030002 00200006 003e0070
00173008  00060003 00000004 00000000 0000000c
00173018  00050011 00000004 711d0770 00172c5c
00173028  0017304c 001712d0 00000000 00000000
00173038  71126ab0 71126ad0 71126b40 71197540
00173048  0017c019 00000080 00000000 00000000
00173058  00000000 00000000 00000000 00000000
00173068  00000000 00000000 00000000 00000000
0:000> !u 0017c011
Unmanaged code
0017c011 b000            mov     al,0
0017c013 eb08            jmp     0017c01d
0017c015 b003            mov     al,3
0017c017 eb04            jmp     0017c01d
0017c019 b006            mov     al,6
0017c01b eb00            jmp     0017c01d
0017c01d 0fb6c0          movzx   eax,al
0017c020 c1e002          shl     eax,2
0017c023 05f02f1700      add     eax,172FF0h
0017c028 e9d7478c00      jmp     00a40804

这是什么,不像是SomeMethod的内容阿,SomeMethod是会调用Console.WriteLine方法的,怎么变成了一些跳转了呢?于是我们想起书本(例如《CLR via C#》)中的话来,在方法第一次调用时,将会跳转到JIT的指令处,对方法的IL代码进行编译。再想想书中的示意图,于是恍然大悟,原来这段代码的作用是“让JIT编译IL”啊。那么在JIT后,同样的调用会产生什么结果呢?

我们在WinDbg中Debug - Detach Debuggee,让程序继续运行。单击回车,您会发现屏幕上出现了Hello Word和After JIT的字样。于是我们继续Attach to Process,重复上面的命令。由于Main方法已经被编译好了,它的汇编代码不会改变,因此在调用SomeMethod方法时的步骤还是不变:先去内存172FF8中读取目标地址,再call至目标地址。

0:000> dd 172FF8
00172ff8  003e00d0 71030002 00200006 003e0070
00173008  00060003 00000004 00000000 0000000c
00173018  00050011 00000004 711d0770 00172c5c
00173028  0017304c 001712d0 00000000 00000000
00173038  71126ab0 71126ad0 71126b40 71197540
00173048  0017c019 00000080 00000000 00000000
00173058  00000000 00000000 00000000 00000000
00173068  00000000 00000000 00000000 00000000
0:000> !u 003e00d0
Normal JIT generated code
TestConsole.Program.SomeMethod()
Begin 003e00d0, size 1a
>>> 003e00d0 55              push    ebp
003e00d1 8bec            mov     ebp,esp
*** WARNING: Unable to verify checksum for mscorlib.ni.dll
003e00d3 e848d3da70      call    mscorlib_ni+0x22d420 (7118d420) (System.Console.get_Out(), mdToken: 06000772)
003e00d8 8bc8            mov     ecx,eax
003e00da 8b153820d102    mov     edx,dword ptr ds:[2D12038h] ("Hello World!")
003e00e0 8b01            mov     eax,dword ptr [ecx]
003e00e2 ff90d8000000    call    dword ptr [eax+0D8h]
003e00e8 5d              pop     ebp
003e00e9 c3              ret

于是我们发现,虽然步骤没有变,但是由于地址172FF8中的值改变了,因此call的目标也变了。新的目标中包含了SomeMethod方法的IL代码编译后的机器码,而我们现在看到便是这个机器码的汇编表现形式。

在《使用WinDbg获得托管方法的汇编代码》一文中我也曾经做过类似的试验,只是这次更简化了一些。在上一次的回复中,有朋友提问说“在ngen之后,是否便可以直接看到这些汇编代码,即使方法还没有被调用过”。我的说法是“可以,但是要观察到这一点并不如现在那样简单”。您能否亲自验证这一点呢?

示例三:泛型方法是为每个类型各生成一份代码吗?

IL和我们平时用的C#程序代码不一样,其中使用了各种指令,而不是像C#那样有类似于英语的关键字,甚至是语法。但是有一点是类似的,它的主要目的是表现程序逻辑,而他们表现得逻辑也大都是相同的,接近的。你创建对象那么我也创建,你调用方法那么我也调用。因此才可以有.NET Reflector帮我们把IL反编译为比IL更高级的C#代码。如果IL把太多细节都展开了,把太多信息都丢弃了,那么怎么可以如此容易就恢复呢?例如,您可以把一篇Word文章转化为图片,那么又如何才能把图片再转回为Word格式呢?C => 汇编、汇编 => C,此类例子数不胜数。

再举一个例子,例如您有以下的范型方法:

private static void GenericMethod<T>()
{
    Console.WriteLine(typeof(T));
}

static void Main(string[] args)
{
    GenericMethod<string>();
    GenericMethod<int>();
    GenericMethod<object>();
    GenericMethod<DateTime>();
    GenericMethod<Program>();
    GenericMethod<double>();

    Console.ReadLine();
}

有朋友认为,范型会造成多份代码拷贝。那么您是否知道,使用不同的范型类型去调用GenericMethod方法,会各生成一份机器码吗?我们先看一下IL吧:

.method private hidebysig static void GenericMethod<T>() cil managed
{
    .maxstack 8
    L_0000: ldtoken !!T
    L_0005: call class [mscorlib]System.Type 
        [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
    L_000a: call void [mscorlib]System.Console::WriteLine(object)
    L_000f: ret 
}

.method private hidebysig static void Main(string[] args) cil managed
{
    .entrypoint
    .maxstack 8
    L_0000: call void TestConsole.Program::GenericMethod<string>()
    L_0005: call void TestConsole.Program::GenericMethod<int32>()
    L_000a: call void TestConsole.Program::GenericMethod<object>()
    L_000f: call void TestConsole.Program::GenericMethod<valuetype [mscorlib]System.DateTime>()
    L_0014: call void TestConsole.Program::GenericMethod<class TestConsole.Program>()
    L_0019: call void TestConsole.Program::GenericMethod<float64>()
    L_001e: ret 
}

这……怎么和我们的C#代码如此接近。嗯,谁让IL清清楚楚明明白白地知道什么叫做“泛型”,于是直接使用这个特性就可以了。所以我们还是用别的办法吧。

其实要了解CLR是否为每个不同类型生成了一份新的机器码,只要看看汇编中是否每次都call到同一个地址中去便可以了。用相同的方法可以看到Main方法的汇编代码如下:

0:003> !u 00a70070
Normal JIT generated code
....Main(System.String[])
Begin 00a70070, size 44
>>> 00a70070 55              push    ebp
00a70071  mov     ebp,esp
// 准备GenericMethod<string>
00a70073  mov     ecx,3A30C4h (MD: ....GenericMethod[[System.String, mscorlib]]())
// 引用类型实际都共享一个GenericMethod<System.__Canon>方法的代码
00a70078  call    dword ptr ds:[3A3098h] (....GenericMethod[[System.__Canon, mscorlib]](), ...)
// 调用GenericMethod<int>
00a7007e  call    dword ptr ds:[3A3108h] (....GenericMethod[[System.Int32, mscorlib]](), ...)
// 准备GenericMethod<object>
00a70084  mov     ecx,3A3134h (MD: ....GenericMethod[[System.Object, mscorlib]]())
// 引用类型实际都共享一个GenericMethod<System.__Canon>方法的代码
00a70089  call    dword ptr ds:[3A3098h] (....GenericMethod[[System.__Canon, mscorlib]](), ...)
// 调用GenericMethod<DateTime>
00a7008f  call    dword ptr ds:[3A3178h] (....GenericMethod[[System.DateTime, mscorlib]](), ...)
// 准备GenericMethod<object>
00a70095  mov     ecx,3A31A4h (MD: ....GenericMethod[[TestConsole.Program, TestConsole]]())
// 引用类型实际都共享一个GenericMethod<System.__Canon>方法的代码
00a7009a  call    dword ptr ds:[3A3098h] (....GenericMethod[[System.__Canon, mscorlib]](), ...)
// 调用GenericMethod<double>
00a700a0  call    dword ptr ds:[3A31E8h] (....GenericMethod[[System.Double, mscorlib]](), ...)
*** WARNING: Unable to verify checksum for C:\...\mscorlib.ni.dll
// 调用Console.ReadLine()
00a700a6  call    mscorlib_ni+0x6d1c24 (71631c24) (System.Console.get_In(), mdToken: 06000771)
00a700ab  mov     ecx,eax
00a700ad  mov     eax,dword ptr [ecx]
00a700af  call    dword ptr [eax+64h]
00a700b2  pop     ebp
00a700b3  ret

从这里我们可以看到,CLR为引用类型(string/object/Program)生成共享的机器码,它们都实际上在调用一个GenericMethod<System.__Canon>所生成的代码。而对于每个不同的值类型(int/DateTime/double),CLR则会为每种类型各生成一份。自然,您有充分的理由说:“调用的目标地址不一样,但是可能机器码是相同的”。此外,CLR的“泛型共享机器码”特性也并非如此简单,如果有多个泛型参数(且引用和值类型“混搭”)呢?如果虽然有泛型参数,但是确没有使用呢?关于这些,您可以自行进行验证。本文的目的在于说明一些问题,并非是要把这一细节给深究到底。

总结

以上三个示例都是用IL无法说明的,而这样的问题其实还有很多,例如:

  • 引用类型和值类型是怎么分配的
  • GC是怎么分代,怎么工作的
  • Finalizer做什么的,对GC有什么影响
  • 拆箱装箱到底做了些什么
  • CLR是怎么验证强签名程序集的
  • 跨AppDomain通信是怎么Marshal by ref或by value的
  • 托管代码是怎么做P/Invoke的
  • ……

您会发现,这些东西虽然无法用IL说明,却其中大部分可以说是最最基本的一些.NET/CLR工作方式的常识,更别说一些细节(数组存放方式,方法表结构)了。它们依旧需要别人来告诉您,您就算学会了IL指令,学会了IL表现逻辑的方式,您还是无法自己知道这些。

IL还是太高级了,太高级了,太高级了……CLR作为承载IL的平台,负担的还是太多。与CPU相比,CLR就像一个溺爱孩子的父母,操办了孩子生活所需要的一切。这个孩子一嚷嚷“我要吃苹果”,则父母就会拿过来一个苹果。您咋看这个孩子,都还是无法了解父母是如何获得苹果的(new一个Apple对象),怎么为孩子收拾残局的(GC)。虽然这些经常是所谓的“成年人(.NET 程序员)必知必会”。而您如果盯着孩子看了半天,耐心分析他吃苹果的过程(使用IL编写的逻辑),最后终于看懂了,可惜发现——tmd老子自己也会吃苹果啊(从C#等高级语言中也能看出端倪来)!不过这一点,还是由下一篇文章来分析和论证吧。

这也是为什么各种.NET相关的书,即使是《CLR via C#》或《Essential .NET》此类偏重“内幕”的书,也只是告诉您什么是IL,它能做什么。然后大量的篇幅都是在使用各种示意图配合高级语言进行讲解,然后通过试验来进行验证,不会盯着IL捉摸不停。同理,我们可以看到《CLR via C#》,《CLR via VB.NET》和《CLR via CLI/C++》,但从来没有过《CLR via IL》。IL还是对应于高级语言,直接对应着.NET特性,而不是CLR的内部实现——既然IL无法说明比高级语言更多的东西,那么为什么要“via IL”?同样的例子还有,MSDN Magazine的CLR Inside Out专栏也没有使用IL来讲解内容,Mono甚至使用了与MS CLR不同实现方式来“编译”相同的IL(Mono是不能参考任何CLR和.NET的代码的,一行都看不得)。你要了解CLR?那么多看看Rotor,多看看Mono——看IL作用不大,它既不是您熟悉CLR的必要条件也不是充分条件,因为您关注的不是对IL的读取,甚至不是IL到机器码的转换方式,而是CLR各处所使用的方案。

最后,我还是想再补充的一句:本文全篇在使用WinDbg进行探索,这并非要以了解IL作为基础,您完全可以不去关心IL那些缤纷复杂的指令的作用是什么。甚至于您完全忽略IL的存在,极端地“认为”是C#直接编译出的机器码,也不妨碍您来使用本文的做法来一探究竟——细节上会有不同,但是看到的东西是一样的。

不过这并不意味着,您不需要了解一些额外的东西。就我看来,您需要具备哪些条件呢?

  • 学习计算机组成原理,计算机体系结构等基础课程的内容,至少是这些课程中的基础。
  • 以事实为基准,而不是“认为是,应该是”的办事方式。
  • 严谨的态度,缜密的逻辑,大胆的推测。
  • ……

“大胆的推测”和“认为是,应该是”并非一个意思。大胆的推测是根据已知现象,运用逻辑进行判断,从而前进,而最终这些推测要通过事实进行确定。正所谓“大胆推测,小心求证”。

以上这些是您“自行进行探索”所需要的条件,而如果您只是要“看懂”某个探索过程的话,就要看“描述”者的表达情况了。一般来说,看懂一个探索过程的要求会低很多,相信只要您有耐心,并且有一些基本概念(与这些条件有关,与IL无关),想要看懂我的探索过程,以及吸收最后的结论应该不是一件困难的事情。

相关文章

所属话题:谈谈IL
Creative Commons License

本文基于署名 2.5 中国大陆许可协议发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名赵劼(包含链接),具体操作方式可参考此处。如您有任何疑问或者授权方面的协商,请给我留言

Add your comment

131 条回复

  1. 老赵
    admin
    链接

    老赵 2009-06-03 14:36:00

    希望能在首页多留一会儿,不会很快就被顶下去。

  2. call111[未注册用户]
    *.*.*.*
    链接

    call111[未注册用户] 2009-06-03 14:39:00

    先顶再看

  3. Da Vinci
    *.*.*.*
    链接

    Da Vinci 2009-06-03 14:47:00

    问老赵一个问题?请问你的文章都什么时候写?难道不上班吗?或者晚上在家写?要花多少时间写? 我看你实在能写,我也想写点,就是没时间,工作就忙的要死,下班了回家也写不了几行。难道你上班的时间写?

  4. 老赵
    admin
    链接

    老赵 2009-06-03 14:53:00

    @Da Vinci
    主要是晚上写,中午吃好饭会再写一会儿。
    晚上可以从8点写到12点,洗个澡上床继续写到1、2点睡觉。

  5. ocean
    *.*.*.*
    链接

    ocean 2009-06-03 14:55:00

    时间就像海绵里的水,只要肯挤,总是有的,呵呵。

  6. 紫色阴影
    *.*.*.*
    链接

    紫色阴影 2009-06-03 15:17:00

    同意老赵的观点,要想了解底层次的东西,就用windbg吧

  7. 啦啦啦1[未注册用户]
    *.*.*.*
    链接

    啦啦啦1[未注册用户] 2009-06-03 15:18:00

    唉,没法子说,老赵这人简直时间富得冒油,但大家一定看到他大部分文章都是晚上2、3点发布的,可见我们老是叹没时间,人家是牺牲了休息时间挤出来的,精力好,身体也应该不错吧,唉,就这样怎么还那么壮!

  8. yeml[未注册用户]
    *.*.*.*
    链接

    yeml[未注册用户] 2009-06-03 15:18:00

    你这篇文章讲得挺好,终于能有力的论证你的观点

  9. Justin
    *.*.*.*
    链接

    Justin 2009-06-03 15:18:00

    难得佳作!

  10. Da Vinci
    *.*.*.*
    链接

    Da Vinci 2009-06-03 15:24:00

    @Jeffrey Zhao
    看来你的确是能写,也的确是没成家。要不早离婚了。

  11. Da Vinci
    *.*.*.*
    链接

    Da Vinci 2009-06-03 15:27:00

    @紫色阴影
    windbg也了解不了什么深层次的东西,最多就是反汇编,看看汇编指令。没必要了解太深,能用就够了。

  12. 老赵
    admin
    链接

    老赵 2009-06-03 15:35:00

    @Da Vinci
    我用WinDbg最多的还是看内存状况,程序运行状态(托管堆/线程/锁, etc)
    这几天读过的汇编数量,是这辈子读过的一半以上。

  13. 老赵
    admin
    链接

    老赵 2009-06-03 15:37:00

    --引用--------------------------------------------------
    Da Vinci: @Jeffrey Zhao
    看来你的确是能写,也的确是没成家。要不早离婚了。
    --------------------------------------------------------
    所以要趁没结婚多写一点么,hoho

  14. 蒙蒙234[未注册用户]
    *.*.*.*
    链接

    蒙蒙234[未注册用户] 2009-06-03 15:41:00

    即使是《CLR via C#》获《Essential .NET》此类偏重“内幕”的书
    老赵你写错了个字“获” 哈哈。

  15. 代震军
    *.*.*.*
    链接

    代震军 2009-06-03 15:50:00

    先收藏了,回头看

  16. 老赵
    admin
    链接

    老赵 2009-06-03 15:51:00

    --引用--------------------------------------------------
    紫色阴影: 同意老赵的观点,要想了解底层次的东西,就用windbg吧
    --------------------------------------------------------
    我觉得吧,还是看Rotor/Mono是正途,WinDbg是汇编,看看数据结构等等不错,看程序逻辑就实在夸张了。
    但是就算看数据结构,也比不上Rotor/Mono这种CLR实现来的直接阿。

  17. 横刀天笑
    *.*.*.*
    链接

    横刀天笑 2009-06-03 15:58:00

    好文。可惜俺的那完工半篇的文章只好胎死腹中了。

  18. chegan
    *.*.*.*
    链接

    chegan 2009-06-03 16:00:00

    非常有说服力,支持老赵

  19. wolf1118baby
    *.*.*.*
    链接

    wolf1118baby 2009-06-03 16:05:00

    文章朴实细腻,看懂了 让我了解不少

  20. 红泥
    *.*.*.*
    链接

    红泥 2009-06-03 16:05:00

    看了这篇,我有想写篇‘很多IL看的到的东西’的冲动了,呵呵。
    IL对于解C#一些语法特性的‘惑’还是很有帮助的,而且IL偏‘高级’,要想看懂也不难。我感觉学学IL还是蛮值得的。

  21. AlexLiu
    *.*.*.*
    链接

    AlexLiu 2009-06-03 16:05:00

    赵老师对技术的态度可谓的严谨的让人嫉妒。

  22. 李亚
    *.*.*.*
    链接

    李亚 2009-06-03 16:07:00

    在看 《CLR via C#》
    很多东西都是作者告诉我们幕后发生了什么,有些真的无法从IL中去证明,至少我目前还不知道如何去求证!

  23. 老赵
    admin
    链接

    老赵 2009-06-03 16:09:00

    @红泥
    支持你,呵呵。不过下一篇我要写得就是:IL看得到的,C#大都也看得到。
    所以……最好红泥兄弟可以写一点“IL看得到,但是C#看不到”的内容。:P
    呃……而且其实第4篇中,就是讲“为什么要学IL,应该怎么学IL”的文章里,会提到一些IL相比C#的优势,如果您已经写的话,说不定我可以引用一下。:)

  24. 老赵
    admin
    链接

    老赵 2009-06-03 16:10:00

    @李亚
    嗯,毕竟IL还是静态的,高级的。

  25. AAAsdfsdfadsf[未注册用户]
    *.*.*.*
    链接

    AAAsdfsdfadsf[未注册用户] 2009-06-03 16:12:00

    博主长的一副欠揍样

  26. 温景良(Jason)
    *.*.*.*
    链接

    温景良(Jason) 2009-06-03 16:14:00

    支持

  27. 老赵
    admin
    链接

    老赵 2009-06-03 16:19:00

    --引用--------------------------------------------------
    AAAsdfsdfadsf: 博主长的一副欠揍样
    --------------------------------------------------------
    顶,支持

  28. 中华小鹰
    *.*.*.*
    链接

    中华小鹰 2009-06-03 16:32:00

    老赵啊,能不能推荐些怎么样用WinDbg进行调试的文章啊?我也想学习下WinDbg,以加深对底层的了解。

  29. Anony[未注册用户]
    *.*.*.*
    链接

    Anony[未注册用户] 2009-06-03 16:37:00

    @中华小鹰
    --引用--------------------------------------------------
    中华小鹰: 老赵啊,能不能推荐些怎么样用WinDbg进行调试的文章啊?我也想学习下WinDbg,以加深对底层的了解。
    --------------------------------------------------------
    可以去网上找一下 SYSINTERNALS Video Library 的视频教学

  30. YinWangLive
    *.*.*.*
    链接

    YinWangLive 2009-06-03 16:50:00

    好文啊!

  31. 青羽
    *.*.*.*
    链接

    青羽 2009-06-03 16:57:00

    上篇看了三遍,这篇是第一遍看。
    又看了一遍,讲的太帅了~~文如其人~~

  32. 别爱上哥,哥只是个传说!
    *.*.*.*
    链接

    别爱上哥,哥只是个传说! 2009-06-03 17:11:00

    没看文章主题,个人建议直接用C或者汇编进行编程..

  33. 第一控制.NET
    *.*.*.*
    链接

    第一控制.NET 2009-06-03 17:15:00

    我被老赵感染,加入健身房跑步大军了……

  34. Dassem[未注册用户]
    *.*.*.*
    链接

    Dassem[未注册用户] 2009-06-03 17:18:00

    @Jeffrey Zhao
    你简直把那位 翻译家 往死里揍了,你让他太相形见绌了。。
    这不是辩论,简直是蹂躏。

    PS. 这是cnblogs的难得好文

  35. 老赵
    admin
    链接

    老赵 2009-06-03 17:21:00

    --引用--------------------------------------------------
    Dassem: @Jeffrey Zhao
    你简直把那位 翻译家 往死里揍了,你让他太相形见绌了。。
    这不是辩论,简直是蹂躏。
    --------------------------------------------------------
    虽然我承认听这话很爽,但是这篇文章真没想要怎么他,而且还刻意不去提及他或他的说法,只是阐述自己的思考结果。

  36. 老赵
    admin
    链接

    老赵 2009-06-03 17:21:00

    --引用--------------------------------------------------
    第一控制.NET: 我被老赵感染,加入健身房跑步大军了……
    --------------------------------------------------------
    这个好,一会儿我也会去。

  37. Avlee
    *.*.*.*
    链接

    Avlee 2009-06-03 17:26:00

    其实很多时候通过看微软的.net Framework源码来了解你的代码写法是否存在性能问题比较实在。

    如果有多个可选择的东西,你不知道用哪个时,我觉得最好根据实际情况编写性能测试代码来考察。

    通过IL或者汇编看到的只是具体的某一个片段的东西,在实际情况中并不一定就是影响问题的真正原因所在。

  38. 老赵
    admin
    链接

    老赵 2009-06-03 17:29:00

    @Avlee
    说的太好了,这正是我下一篇文章中想说的。
    对于性能问题,最好的办法是性能测试,想分析原因,用Profiler配合观察高级代码。
    用IL和汇编判断性能问题,容易把思路搞乱,纠缠于细节。

  39. Anders Liu
    *.*.*.*
    链接

    Anders Liu 2009-06-03 17:35:00

    --引用--------------------------------------------------
    Jeffrey Zhao: --引用--------------------------------------------------
    AAAsdfsdfadsf: 博主长的一副欠揍样
    --------------------------------------------------------
    顶,支持
    --------------------------------------------------------
    顶 too

  40. 四有青年
    *.*.*.*
    链接

    四有青年 2009-06-03 17:39:00

    长见识拉

  41. alonesail[未注册用户]
    *.*.*.*
    链接

    alonesail[未注册用户] 2009-06-03 17:46:00

    个人技术的定位问题。大部分人多半是做应用开发的,底层的东西不一定需要十分的了解,重要的还是产品要做到好。

  42. 上述搜索[未注册用户]
    *.*.*.*
    链接

    上述搜索[未注册用户] 2009-06-03 17:47:00

    此人乃天生钻研技术的料子,国内应该多出点,鉴定完毕!

  43. wanchangpeng
    *.*.*.*
    链接

    wanchangpeng 2009-06-03 17:50:00

    楼主研究这个有用么?研究这个生活能改善么?做应用软件关键是站在用户的
    角度来看问题吧

  44. 老赵
    admin
    链接

    老赵 2009-06-03 17:52:00

    --引用--------------------------------------------------
    wanchangpeng: 楼主研究这个有用么?研究这个生活能改善么?做应用软件关键是站在用户的角度来看问题吧
    --------------------------------------------------------
    有没有用,能不能改善生活我不知道。
    不过我的确不提倡在可以有其他办法的时候,使用IL和WebDbg查看问题,接下去会提到的。
    我本身也是倾向于不去钻研IL的,目前是为了描述问题而已。

  45. 老赵
    admin
    链接

    老赵 2009-06-03 17:54:00

    --引用--------------------------------------------------
    alonesail: 个人技术的定位问题。大部分人多半是做应用开发的,底层的东西不一定需要十分的了解,重要的还是产品要做到好。
    --------------------------------------------------------
    应用了底层了也是相对的,有时候也不那么容易分,所以讨论讨论无妨。
    这系列文章的目的也是探讨出一些可供参考的东西,一个人过来看了,知道自己应不应该学,或怎么学IL等等,嗯嗯。

  46. 上述搜索[未注册用户]
    *.*.*.*
    链接

    上述搜索[未注册用户] 2009-06-03 18:00:00

    老赵对Silverlight好像不是很热衷?为什么?
    对Asp.net现在介绍的也少了
    倒是研究基础的东西了
    不如介绍点asp.net4.0的新东西

  47. feilng[未注册用户]
    *.*.*.*
    链接

    feilng[未注册用户] 2009-06-03 18:05:00

    IL 只是在CLR的抽象级别上说明干什么,而不是怎么干
    汇编语言只是在CPU接口层次上说明干什么,而不是怎么干,
    怎么干是由最终的cpu指令以及cpu微程序实现决定的,汇编语言同样隐藏了这个这些东西

    都是接口而已,层层封装,隐藏实现,只是层次不同而已

  48. 老赵
    admin
    链接

    老赵 2009-06-03 18:07:00

    @上述搜索
    Silverlight,WPF都偏表现了啊,这些东西的特点就是:就算你精通了你也觉得缺一门。因为它们还需要设计,设计不出好看的好用的东西精通那些也没有大用。
    同样道理,我搞ASP.NET,我搞JS编程,但我不搞CSS,这些我倒都想清楚了。
    ASP.NET的话,该讲的好像都已经讲的差不多了啊,没话题了。介绍新东西我倒一直不太热衷,不是说不喜欢新事物,是不喜欢“介绍”。
    基础东西我一直不放弃的,只是以前没有怎么写出来,没有东西来“触发”我写得欲望,总归要有个好角度是吧。

  49. 老赵
    admin
    链接

    老赵 2009-06-03 18:08:00

    @feilng
    嗯,没错,CPU上的流水线,并行,内存模型,Cache Lock等东西都是在汇编/机器码上体现不出来的。

  50. feilng[未注册用户]
    *.*.*.*
    链接

    feilng[未注册用户] 2009-06-03 18:09:00

    重要的是要清楚在现实条件下,需要进入那个层次才能获取足够的信息,掌握接口的完整语义和潜在副作用。

  51. feilng[未注册用户]
    *.*.*.*
    链接

    feilng[未注册用户] 2009-06-03 18:10:00

    只是现实中我们用人家给的API,但是API深层次的各种作用,并没有明确界定
    契约不清晰,我们只能往下钻自己看看

  52. 老赵
    admin
    链接

    老赵 2009-06-03 18:10:00

    --引用--------------------------------------------------
    feilng: 重要的是要清楚在现实条件下,需要进入那个层次才能获取足够的信息,掌握接口的完整语义和潜在副作用。
    --------------------------------------------------------
    说的太好了,以后写文章的时候借我用一下。

  53. chegan
    *.*.*.*
    链接

    chegan 2009-06-03 18:22:00

    --引用--------------------------------------------------
    Jeffrey Zhao: --引用--------------------------------------------------
    AAAsdfsdfadsf: 博主长的一副欠揍样
    --------------------------------------------------------
    顶,支持
    --------------------------------------------------------
    老赵心态很好啊,支持你,继续写下去

  54. 躺着读书[未注册用户]
    *.*.*.*
    链接

    躺着读书[未注册用户] 2009-06-03 18:23:00

    都怪微软写得不清楚。否则这些看规范就行了,用不着看什么IL了。

  55. 幸存者[未注册用户]
    *.*.*.*
    链接

    幸存者[未注册用户] 2009-06-03 18:31:00

    --引用--------------------------------------------------
    feilng: 只是现实中我们用人家给的API,但是API深层次的各种作用,并没有明确界定
    契约不清晰,我们只能往下钻自己看看
    --------------------------------------------------------
    这其实应该是规范和实现的区别了。我们能看到的其实就是规范,看不到或很难看到的是实现。规范规定了这些接口、API应该是什么样,这些是标准,具体实现遵循了标准,但是肯定有标准描述不到的地方。作为一个使用者,一般来说知道标准就行了,因为不同的实现其底层细节可能完全不一样,在CLR中是这样,在Mono中很可能是那样;在CLR2中是这样,在CLR4中很可能是那样。

  56. Zhenway
    *.*.*.*
    链接

    Zhenway 2009-06-03 20:40:00

    示例一,是因为有JIT优化,太过依赖具体了,ECMA335标准中VES并没有指出必须要有这样的优化
    换程汇编,不同写法可能会被会被不同的CPU执行出不同的结果,可能在Intel的CPU上,A代码比B代码快,而在AMD的CPU上,B代码比A代码快

    示例三,是因为所有的引用类型在CLR里面都被当成隐藏的o类型,ECMA335中间写过了,没看过的人才会这样认为

  57. secondflying[未注册用户]
    *.*.*.*
    链接

    secondflying[未注册用户] 2009-06-03 20:40:00

    佩服老赵严谨的态度。
    我也姓赵,差别哪这么大咧!!

  58. 幸存者[未注册用户]
    *.*.*.*
    链接

    幸存者[未注册用户] 2009-06-03 20:45:00

    --引用--------------------------------------------------
    “别人可能还会告诉你”,多态是靠对象地址加偏移;
    --------------------------------------------------------
    这句有问题吧,真的是“对象地址”吗?难道相同的类的不同实例都有自己的方法表吗?

  59. 老赵
    admin
    链接

    老赵 2009-06-03 21:54:00

    --引用--------------------------------------------------
    幸存者: 这句有问题吧,真的是“对象地址”吗?难道相同的类的不同实例都有自己的方法表吗?
    --------------------------------------------------------
    多谢提醒,已经改为方法表加偏移量,查了Essential .NET,应该没有问题了。

  60. 老赵
    admin
    链接

    老赵 2009-06-03 21:57:00

    @Zhenway
    示例一:说的没错,严格说来,我只是证明了在我特定条件下(写法,平台,优化策略,etc)的结果。
    示例三:您可以说得再具体一些吗?例如分享一下看ECMA的心得,对您有什么帮助等等。

  61. OwnWaterloo
    *.*.*.*
    链接

    OwnWaterloo 2009-06-03 22:16:00

    顶老赵。
    “.Net范型会对不同的值类型产生不同的代码,对引用类型产生相同代码”,我只能如此猜测,需要“别人来证明”。
    现在你证明了, 我就不用猜测了, 谢谢~~~

    继续顶老赵的治学态度。
    对于那些鼠目寸光的人,我只想说,“自己不愿学习是自己的事,但阻止别人讨论与学习,就是找抽了”。


    包括那个对范型似懂非懂,一知半解,没有任何证据就排斥范型的人。
    (他以前还发过一篇什么,臆测.Net中的List<T>以链表实现,还对别人写的范型代码嗤之以鼻)。
    .Net中有LinkedList<T>。就算是我这种不用.Net的人,猜也能猜出List<T>肯定不是链表…… 搞笑……


    包括最近的"OO有道"。其中有人甚至发出呻吟:"为什么没有一个OO"?
    真好笑, 为什么一定要有OO?
    即使ACMer写出的代码通常不具备通用性,能更有效提高其通用性的方式也是范型而不是OO。

    包括一些动不动就以“产品,应用”来敷衍的人。


    还有一些文章也想评论…… 不过还是不能订阅评论……
    目前能想到的办法就是订阅评论的rss, 但是老赵的评论rss…… 内容是很丰富的 ………………
    实在没办法就去注册个cnblogs算了…… 浪费它们的网络资源~~~

  62. 老赵
    admin
    链接

    老赵 2009-06-03 22:20:00

    @OwnWaterloo
    其实吧,我觉得,写一个程序读取HTML,把评论内容分析出来,也不是一件难事,呵呵。
    嗯嗯,就我做一下吧,应该花不了多少时间。

  63. 老赵
    admin
    链接

    老赵 2009-06-03 23:10:00

    @DiggingDeeply
    只有第一次访问过后才会生成某个类型对应泛型方法的机器码。
    例如,没有调用GenericMethod<int>之前是不会有int版本的机器码的。

  64. mikelij
    *.*.*.*
    链接

    mikelij 2009-06-03 23:13:00

    呵呵,这些可以揭示CLR的某些细节。佩服你专研精神。还是支持你!
    除此之外想说:(这是我个人意见,不同意也没有关系, 呵呵)你提到的IL高级特性,例如泛型、引用类型,值类型,方法属性等等,其实都是BCL提供的。严格地说, IL是.net VM的语言。.net VM包括几大部件, 执行引擎, 垃圾收集器, Jit编译器等。有了这几个部件就可以运行IL程序了。那些高级特性其实都是BCL提供的,非必须的。.net VM如果不用这些BCL提供的东西。应该是也能运行,如果我们有类似于BCL的一套类库,应该也能运行于.net VM。不过我没有去做这种试验。算我臆测吧。呵呵。

  65. 老赵
    admin
    链接

    老赵 2009-06-03 23:17:00

    @mikelij
    泛型、引用类型,值类型,方法、属性这些也是定义在CLR中的概念吧,IL也是知道这些概念的。BCL就是指提供的一堆框架,类库。

  66. 老赵
    admin
    链接

    老赵 2009-06-03 23:32:00

    @DiggingDeeply
    但也只有“运行到了”,才会生成啊。如果你就跑一小部分功能,就不会生成那些类了。
    JIT的最小单位是“方法”,JIT某个方法时,如果方法内部用到的具体泛型类才会生成(也有可能是真正使用那个具体泛型类才生成的,那就更迟,更省资源了)。

  67. mikelij
    *.*.*.*
    链接

    mikelij 2009-06-03 23:39:00

    值类型定义于System.ValueType下. 泛型也是System.Collection.Generic.
    引用类型只要用class等关键字声明,编译器就会将其继承于System.Object. 方法属性是System.Reflection之下定义的?
    假设我们把整个BCL都不要,换成另外一个库.按道理.net VM是还是一个完整的VM,它应该还能运行IL.什么压栈,取操作数,call一个地址的子程序等等,都应该如常进行。类就一定要继承于System.object吗,那其实是编译默认做的事情。

  68. DiggingDeeply
    *.*.*.*
    链接

    DiggingDeeply 2009-06-03 23:40:00

    @Jeffrey Zhao
    泛型类型实例是appdomain全局共享的还是全domain共享的。
    是每个domian一个还是全部domain就一个。我忘了。

  69. DiggingDeeply
    *.*.*.*
    链接

    DiggingDeeply 2009-06-03 23:42:00

    --引用--------------------------------------------------
    mikelij: 值类型定义于System.ValueType下. 泛型也是System.Collection.Generic.
    引用类型只要用class等关键字声明,编译器就会将其继承于System.Object. 方法属性是System.Reflection之下定义的?
    假设我们把整个BCL都不要,换成另外一个库.按道理.net VM是还是一个完整的VM,它应该还能运行IL.什么压栈,取操作数,call一个地址的子程序等等,都应该如常进行。类就一定要继承于System.object吗,那其实是编译默认做的事情。
    --------------------------------------------------------
    站在C#上,类一定继承object;站在IL上,不一定。

  70. 老赵
    admin
    链接

    老赵 2009-06-03 23:46:00

    @mikelij
    是啊,你说的没错。但是引用类型、值类型、泛型等概念还是CLR和IL上有的啊。
    只是你可以定义一套新的BCL,然后有个P#语言,把C#这些限制去掉而已。
    就像你会发现,IL里是由.ref,class,valuetype等指令或关键字的。
    也就是说,你可以随意定新的BCL,但是它必须有引用类型,值类型,泛型这些概念体现在里面,名字可以随意取,比如叫MySystem.NotObject等等。

  71. 老赵
    admin
    链接

    老赵 2009-06-03 23:47:00

    --引用--------------------------------------------------
    DiggingDeeply: @Jeffrey Zhao
    泛型类型实例是appdomain全局共享的还是全domain共享的。
    是每个domian一个还是全部domain就一个。我忘了。
    --------------------------------------------------------
    印象中,除了mscrolib里的类型是process共享的,其他都是appdomain共享的。

  72. mikelij
    *.*.*.*
    链接

    mikelij 2009-06-03 23:51:00

    --引用--------------------------------------------------
    DiggingDeeply: --引用--------------------------------------------------
    mikelij: 值类型定义于System.ValueType下. 泛型也是System.Collection.Generic.
    引用类型只要用class等关键字声明,编译器就会将其继承于System.Object. 方法属性是System.Reflection之下定义的?
    假设我们把整个BCL都不要,换成另外一个库.按道理.net VM是还是一个完整的VM,它应该还能运行IL.什么压栈,取操作数,call一个地址的子程序等等,都应该如常进行。类就一定要继承于System.object吗,那其实是编译默认做的事情。
    --------------------------------------------------------
    站在C#上,类一定继承object;站在IL上,不一定。
    --------------------------------------------------------
    是哦. 我就觉得IL与高级语言特性没有关系. 所谓高级特性都与BCL有关。BCL是Microsoft的一个商业类库. 呵呵用了C++时代的词汇--商业类库。如果用IL编程序,不用BCL任何东西。应该还是能运行的。只不过没有商业库,做不了多少事情。没有BCL,就象起房子从做砖开始。

  73. 老赵
    admin
    链接

    老赵 2009-06-03 23:55:00

    @mikelij
    我的看法是,BCL可以新作一套,但是一定也要满足某些特性,例如支持泛型,有引用类型,值类型,有方法有属性。
    因为IL是要去“识别”它们的,如果它们没有这些特性,IL就不能直接使用了(或者说,缺少特性着用)。

  74. mikelij
    *.*.*.*
    链接

    mikelij 2009-06-03 23:57:00

    --引用--------------------------------------------------
    Jeffrey Zhao: @mikelij
    是啊,你说的没错。但是引用类型、值类型、泛型等概念还是CLR和IL上有的啊。
    只是你可以定义一套新的BCL,然后有个P#语言,把C#这些限制去掉而已。
    就像你会发现,IL里是由.ref,class,valuetype等指令或关键字的。
    也就是说,你可以随意定新的BCL,但是它必须有引用类型,值类型,泛型这些概念体现在里面,名字可以随意取,比如叫MySystem.NotObject等等。
    --------------------------------------------------------
    我有种感觉: IL的class 和高级语言的class差别比较远. 我没有深入这个问题。我上述说法只是我一个臆测。其实你所说,DiggingDeeply所说,还有我所说,都不足以证明什么。还是有待证明。

  75. mikelij
    *.*.*.*
    链接

    mikelij 2009-06-04 00:04:00

    --引用--------------------------------------------------
    Jeffrey Zhao: @mikelij
    我的看法是,BCL可以新作一套,但是一定也要满足某些特性,例如支持泛型,有引用类型,值类型,有方法有属性。
    因为IL是要去“识别”它们的,如果它们没有这些特性,IL就不能直接使用了(或者说,缺少特性着用)。
    --------------------------------------------------------
    支持泛型,有引用类型,值类型,有方法有属性, 那些都属于商业功能。没有这些只是没有这些商业功能。但是IL还是IL. 它是VM的语言。
    语言和商业库还是有区别的。Intel开发CPU的时候,它会定义CPU的指令集, 就构成了汇编语言。Microsoft开发了.net VM,相当于一台机器,它也有语言。这个语言里面肯定不包括那些商业功能。那些商业功能应该是在这个语言之上的。

  76. 老赵
    admin
    链接

    老赵 2009-06-04 00:04:00

    @mikelij
    呵呵,不过讨论讨论总是可以的。
    你认为IL的class和C#的class有什么区别呢?
    除了C#编译器默认继承System.Object外,我觉得这点说明不了什么问题……

  77. 老赵
    admin
    链接

    老赵 2009-06-04 00:10:00

    @mikelij
    我的看法正好和你相反。
    我认为对于泛型,引用类型的支持,是内置在IL中的,VM也是需要这些支持的。如果没有这些特性,IL就是另外一种东西了。
    就好比有些CPU架构会给出几个特殊指令用于浮点数计算一样,这些都属于IL语言的功能。
    如果编译器无法生成这些指令,就无法用足CPU的功能了。

  78. mikelij
    *.*.*.*
    链接

    mikelij 2009-06-04 00:11:00

    --引用--------------------------------------------------
    Jeffrey Zhao: @mikelij
    呵呵,不过讨论讨论总是可以的。
    你认为IL的class和C#的class有什么区别呢?
    除了C#编译器默认继承System.Object外,我觉得这点说明不了什么问题……
    --------------------------------------------------------
    算我提出了一个有待证明的问题。至少我觉得你说的IL具有高级特性需要打打问号。
    BTW, 给其他人说一句: 看别人文章,要辩证地看。这样对别人和对自己都是提高。

  79. 老赵
    admin
    链接

    老赵 2009-06-04 00:14:00

    @mikelij
    其实我已经知道你的观点了,只是我还想知道你的更具体的看法,比如你为什么觉得需要打问号等等……所以要讨论么,呵呵。

  80. mikelij
    *.*.*.*
    链接

    mikelij 2009-06-04 00:24:00

    --引用--------------------------------------------------
    Jeffrey Zhao: @mikelij

    我的看法正好和你相反。

    我认为对于泛型,引用类型的支持,是内置在IL中的,VM也是需要这些支持的。如果没有这些特性,IL就是另外一种东西了。

    就好比有些CPU架构会给出几个特殊指令用于浮点数计算一样,这些都属于IL语言的功能。

    如果编译器无法编译出这些指令,就无法用足CPU的功能了。
    --------------------------------------------------------
    .net 1.0 1.1就没有泛型。至少可以说的是泛型在.net 1.x时代就不是内置的。后来泛型是怎么加上的呢?是在IL?还是在BCL? 我目前觉得泛型是在BCL中加上的。你说的硬件CPU绑定一些商业功能也有。Intel, AMD的CPU就有一些多媒体指令。IL现在绑定多少,还有待商榷。总的感觉IL不太可能将许多商业功能内置。所以有不少是由BCL提供的。

  81. 老赵
    admin
    链接

    老赵 2009-06-04 00:29:00

    @mikelij
    不同版本的IL自然有不同的功能,这是很正常的啊。因为CLR升级了,于是IL跟着一起增强,于是BCL也可以增强了。如果只是增强在BCL中,不增强IL,那么又怎么能用呢?
    其实BCL和IL的关系是很紧密的,所以也可以这么说:因为BCL需要,所以IL必须增加功能,因此IL也内置了一些新的功能了。
    所以我的看法是,IL肯定是带大量高级功能的,而且这高级功能会随着CLR升级而补充新的指令和特性进去,于是BCL也可以使用了。

  82. mikelij
    *.*.*.*
    链接

    mikelij 2009-06-04 00:30:00

    问个问题.纯粹用IL编一个程序。写一个类,这个类会不会继承System.Object?如果不, 也许可以发现点什么.

  83. 老赵
    admin
    链接

    老赵 2009-06-04 00:31:00

    @mikelij
    可以不继承System.Object,不过这是程序/编译器的共同选择吧。
    IL内置了继承功能,内置了引用类型,泛型等功能。
    但是肯定不会阻止你写一个程序,不去使用那些特性。
    不阻止,不代表它没有内置高级功能啊。而且,你说的“类”,它不就是一个高级功能吗?

  84. mikelij
    *.*.*.*
    链接

    mikelij 2009-06-04 00:42:00

    --引用--------------------------------------------------
    Jeffrey Zhao: @mikelij

    可以不继承System.Object,不过这是程序/编译器的共同选择吧。

    IL内置了继承功能,内置了引用类型,泛型等功能。

    但是肯定不会阻止你写一个程序,不去使用那些特性。

    不阻止,不代表它没有内置高级功能啊。而且,你说的“类”,它不就是一个高级功能吗?
    --------------------------------------------------------
    呵呵,那个"类"只能算IL中的class, 和c#之类高级语言中的类还是有区别的。高级语言的类继承了System.object, 就自动享有System.object的一些东西。而这个IL中的类没有享有那些特性。说起来那些特性更象商业功能。属于商业库范畴。假设这个纯IL的类在没有BCL, 没有继承System.Object的情况下,也能运行,是不是说明IL没有高级特性。

  85. 老赵
    admin
    链接

    老赵 2009-06-04 00:44:00

    @mikelij
    原来你是这个意思。我们对于“高级特性”的定义不同。
    我认为IL的“继承”,“引用类型”,“值类型”,“泛型”等已经是“高级特性”了。
    而你认为C#的那些属于“高级特性”,那么IL的确没有那么高的要求了。
    C#编译器对IL的功能做出一点限制而已,BCL还是利用了IL的那些我认为的“高级特性”。

  86. andy.he
    *.*.*.*
    链接

    andy.he 2009-06-04 00:45:00

    CLR的能力决定一切。
    不过可以肯定的是,为C#增加泛型这样的特性,不是增强了C#编译器,就是增强了CLR.与IL似乎关联不大。

    呵呵,在下C#初学者, 积极参加讨论而已~

  87. 老赵
    admin
    链接

    老赵 2009-06-04 00:50:00

    @mikelij
    我认为C#的类和IL的类的确是一个概念。
    只是C#编译器强制每个类一定要继承Object,而IL本身并没有做出这个限制。除此之外,在其他地方,例如使用规则上并无二致。
    也就是说C#中的类型,其实是IL可用类型的子集。C#用了IL功能的一部分,IL可以做得一些事情,C#做不了。

  88. 老赵
    admin
    链接

    老赵 2009-06-04 00:52:00

    @andy.he
    C#编译器生成的是IL,然后才能给CLR使用。
    IL还要服务于其他语言,怎么可能不随着CLR更新呢?
    // 还是我没有理解你的意思……

  89. andy.he
    *.*.*.*
    链接

    andy.he 2009-06-04 00:54:00

    @Jeffrey Zhao

    恩,是一个概念。
    都属于OO理念的实现。 哈哈~

  90. andy.he
    *.*.*.*
    链接

    andy.he 2009-06-04 00:59:00

    @Jeffrey Zhao

    呵呵,可能我表达得不清楚。我的意思是,为C#这门语言增加一个MILESTONE级的功能,要做的第一件事情,无非是下面两种情况之一: 增强CLR,抑或增强C#编译器。 至于再扩展IL是第二件事情了~

  91. 老赵
    admin
    链接

    老赵 2009-06-04 01:01:00

    @andy.he
    这话似乎挺有道理的。
    如果能够从编译器角度增强,那么就不会去动IL,CLR。例如C# 3.0里的各种特性。
    如果做不到,那么就必须动CLR了,例如.NET 2.0的泛型等等,这时候因为CLR需要,因此势必要加上一点IL。

  92. mikelij
    *.*.*.*
    链接

    mikelij 2009-06-04 01:03:00

    @Jeffrey Zhao
    其实,说IL具有高级特性, 不管这个"高级特性"定义如何,也不能完全算错。只是这里面有些内涵。不容易搞清楚。谢了,陪我讨论到这么晚。呵呵.睡觉了.

  93. 老赵
    admin
    链接

    老赵 2009-06-04 01:03:00

    评论RSS订阅做好了,明天又可以发布一个小玩意儿,呵呵。

  94. 老赵
    admin
    链接

    老赵 2009-06-04 01:04:00

    @mikelij
    我也睡了,有机会多多交流,呵呵。

  95. andy.he
    *.*.*.*
    链接

    andy.he 2009-06-04 01:09:00

    @Jeffrey Zhao
    恩,我要表达的正式这个意思。看来我的communication能力还不行~

    哈哈,其实看赵兄的文章也有将近一个月了。赵兄的逻辑思维能力与表达能力以及技术小弟都是很佩服的。尤其是赵兄的为人谈吐,我觉得非常具有人性,很open,建立一个良好的交流氛围很需要赵兄这种方式~ 希望赵兄保持这种方式,不要因外力影响而改变!
    难道文艺复兴真的注定要在我们IT人中发起? 呵呵,笑~ joke,joke。~

  96. Ltaos
    *.*.*.*
    链接

    Ltaos 2009-06-04 03:03:00

    老赵写的东西,还是看得进去的。感觉第一篇文章很好,清晰地了解许多东西。如果大牛门,能够证明没有学习CIL的必要性,估计价值是很大的。象我这样从门外汉自学的,没有太多的时间,就不用将时间花在学习CIL上面了。属于这种类型的人,估计有不少。所以不学CIL,其实是一个重要也很实用的主题。
    不过虽然是从门外汉自学的,却对.NET Framework类库、CLR(包括其中的公共类型系统、公共语言系统等)、C#等具有筑基性的认识。研究过《C#编程语言详解》(电子)(即《C#语言规范》)等。注:《C#语言规范》的Word版本,可以从Visual Studio的目录中,搜索*.doc,即可得到。VS2005中的是《C#语言规范2.0》,VS2008中的是《C#语言规范3.0》。
    另外,还有其它的重要方法,估计能够将C#学习得神乎其技,可能性是很大的。由于不是主要研究方向,也不想多讲。总之,有大牛提出了不学CIL这一主题,在相当长的时间内,可以不考虑这个问题了。这样节省了时间和精力。

  97. 技术爱好者
    *.*.*.*
    链接

    技术爱好者 2009-06-04 06:26:00

    在我的印象中IL中不过是为了适应多平台吧,别无他用.当然我没有研究过

  98. DiggingDeeply
    *.*.*.*
    链接

    DiggingDeeply 2009-06-04 06:50:00

    泛型类型就是通过!T来占位,在JIT的时候确定类型T来生成目标代码。

  99. stalling240(老S)
    *.*.*.*
    链接

    stalling240(老S) 2009-06-04 08:53:00

    老赵对技术的态度可谓的严谨的令人发指~~~

  100. 老赵
    admin
    链接

    老赵 2009-06-04 08:58:00

    @Ltaos
    这个意见肯定无法统一,我也只是阐述我的观点,经可能说得有凭有据令人信服。
    但是,如果那么容易就让别人完全同意,那么社区可以不要搞了,搞独裁算了,嗯嗯。
    肯定也有人有自己看法的,如果大家说清楚了就好,每个人过来能判断出来就行。

  101. Tristan G
    *.*.*.*
    链接

    Tristan G 2009-06-04 09:37:00

    无敌了,顶一下。

  102. 韦恩卑鄙
    *.*.*.*
    链接

    韦恩卑鄙 2009-06-04 10:46:00

    --引用--------------------------------------------------
    红泥: 看了这篇,我有想写篇‘很多IL看的到的东西’的冲动了,呵呵。
    IL对于解C#一些语法特性的‘惑’还是很有帮助的,而且IL偏‘高级’,要想看懂也不难。我感觉学学IL还是蛮值得的。

    --------------------------------------------------------
    用 reflector 只要把c#和vb比较下就真相大白了 不一定要看il
    不是说il不重要 但是有现成的il专家们作的工具可以用 很方便

  103. 韦恩卑鄙
    *.*.*.*
    链接

    韦恩卑鄙 2009-06-04 10:48:00

    --引用--------------------------------------------------
    andy.he: @Jeffrey Zhao
    恩,我要表达的正式这个意思。看来我的communication能力还不行~

    哈哈,其实看赵兄的文章也有将近一个月了。赵兄的逻辑思维能力与表达能力以及技术小弟都是很佩服的。尤其是赵兄的为人谈吐,我觉得非常具有人性,很open,建立一个良好的交流氛围很需要赵兄这种方式~ 希望赵兄保持这种方式,不要因外力影响而改变!
    难道文艺复兴真的注定要在我们IT人中发起? 呵呵,笑~ joke,joke。~
    --------------------------------------------------------
    兄弟你加入英文可以 麻烦要地道点 :P

  104. 韦恩卑鄙
    *.*.*.*
    链接

    韦恩卑鄙 2009-06-04 10:51:00

    --引用--------------------------------------------------
    技术爱好者: 在我的印象中IL中不过是为了适应多平台吧,别无他用.当然我没有研究过
    --------------------------------------------------------
    我感觉这句话虽然不太自信,但是似乎接触到了核心问题

    原始的存在需求 决定了事务的本质

    如果c#组的编译器没做那么多暗扣的话。 研究il 这一层多少可以再放松下。

  105. 老赵
    admin
    链接

    老赵 2009-06-04 11:11:00

    --引用--------------------------------------------------
    韦恩卑鄙: 用 reflector 只要把c#和vb比较下就真相大白了 不一定要看il
    不是说il不重要 但是有现成的il专家们作的工具可以用 很方便。
    --------------------------------------------------------
    我同意,我几乎只看C#的。

  106. 路过的[未注册用户]
    *.*.*.*
    链接

    路过的[未注册用户] 2009-06-04 13:24:00

    老赵,好文章,要顶。。。
    要是你翻译CLR VIA C#,我一定买一本
    顺便说一句:博客园同时提交评论,验证码会验证不过。验证码存在Session还是Cookie里,为什么并发会有问题,不是第一次出现这个bug了。

  107. 老赵
    admin
    链接

    老赵 2009-06-04 13:35:00

    @路过的
    因为cookie是共享的,不是每窗口独立的。

  108. 路过的[未注册用户]
    *.*.*.*
    链接

    路过的[未注册用户] 2009-06-04 13:46:00

    谢谢解答。
    那就是说被其他被其他网站验证码cookie覆盖了?

  109. 老赵
    admin
    链接

    老赵 2009-06-04 13:48:00

    @路过的
    比如:
    先打开页面A,生成cookie a,对应验证码1234。
    再打开页面B,生成cookie b,对应验证码5678,覆盖了cookie a。
    于是5678提交后,1234就验证不通过了。 // A和B是同一个网站的两个页面。

  110. 翻译家[未注册用户]
    *.*.*.*
    链接

    翻译家[未注册用户] 2009-06-04 14:35:00

    "小赵,你写得让我没办法写驳文2了,惭愧ing"

  111. 老赵
    admin
    链接

    老赵 2009-06-04 15:30:00

    @翻译家
    我倒觉得他应该正在写驳文2,否则今天他不会没有动静的,我们期待一下吧。

  112. andy.he
    *.*.*.*
    链接

    andy.he 2009-06-04 20:19:00

    @韦恩卑鄙
    靠~! 哈哈,我哪个词说的不地道? 麻烦卑鄙兄指出来~ 像赵兄说过的,给结论不给论证,不是良好的讨论方式~

  113. communication[未注册用户]
    *.*.*.*
    链接

    communication[未注册用户] 2009-06-04 21:19:00

    @andy.he
    哈哈,卑鄙兄是说你的“communication能力”

  114. andy.he
    *.*.*.*
    链接

    andy.he 2009-06-04 21:45:00

    @communication
    “ communication”这个词绝对地道。。。不信大家说着试试,~

  115. 韦恩卑鄙
    *.*.*.*
    链接

    韦恩卑鄙 2009-06-05 13:39:00

    --引用--------------------------------------------------
    Anders Liu: --引用--------------------------------------------------
    Jeffrey Zhao: --引用--------------------------------------------------
    AAAsdfsdfadsf: 博主长的一副欠揍样
    --------------------------------------------------------
    顶,支持
    --------------------------------------------------------
    顶 too
    --------------------------------------------------------
    顶 three

  116. 韦恩卑鄙
    *.*.*.*
    链接

    韦恩卑鄙 2009-06-05 13:40:00

    --引用--------------------------------------------------
    andy.he: @communication
    “ communication”这个词绝对地道。。。不信大家说着试试,~
    --------------------------------------------------------
    Joke Joke 别扭阿

    阿油鸡丁咪?

  117. 韦恩卑鄙
    *.*.*.*
    链接

    韦恩卑鄙 2009-06-05 13:46:00

    communication 很地道 但是后面跟了个中文词能力

    别让communication skill 妻离子散吧 多少也有点别扭

    当然也可能我语感没到家 乱说哦:P

  118. qingyou28[未注册用户]
    *.*.*.*
    链接

    qingyou28[未注册用户] 2009-06-06 10:19:00

    确实佩服老赵对技术的执着,虽然我也一直做企业级开发,我对做应用软件的理解是,软件做的好坏,只有20%是在于技术层面,80%是其他方面,包括你的思路、创意、审美等等。以至于做大型企业开发里,往往是业务分析师地位比较高也重要,而且要做好的软件,不能有太多的技术思维,而是要站在用户的角度来理解。

  119. 小猴子
    *.*.*.*
    链接

    小猴子 2009-06-08 11:08:00

    --引用--------------------------------------------------
    qingyou28: 确实佩服老赵对技术的执着,虽然我也一直做企业级开发,我对做应用软件的理解是,软件做的好坏,只有20%是在于技术层面,80%是其他方面,包括你的思路、创意、审美等等。以至于做大型企业开发里,往往是业务分析师地位比较高也重要,而且要做好的软件,不能有太多的技术思维,而是要站在用户的角度来理解。
    --------------------------------------------------------
    确实是那样的。不过这是两个话题了,现在他们在讨论工具本身的问题,以后有好帖子,可以讨论下另外80%的的东西。

  120. KAYAK
    *.*.*.*
    链接

    KAYAK 2009-08-08 10:26:00

    正在培训.net...(有一定的基础,来深入的学习下),还好,不是北大青鸟,哈哈。在培训中收获很大,现在正在进行framework 泛型、集合、io、xml的学习,类库之强大,对象之间关系之错综复杂,感觉有些晕,想来看看老赵有没有相关的文章,无意翻到了这页,感觉归根结底是因为.net是二次编译的,有些功能是实现在c#代码向il映射的过程,有些是实现在il向机器码转化的过程,看过anytao的书,关于委托、事件、lambda表达式的探究中,其实他们在c#映射到il语言这一块都是一样的,不同体现在il到机器码的映射上。正因为二次编译,有些功能通过il看不出来也就自然而然了。不知道这样理解是否正确。另外,希望您能给学习framework提些建议。

  121. 老赵
    admin
    链接

    老赵 2009-08-08 12:42:00

    @KAYAK
    虽然我认为IL看不出很多东西,但我倒不是这个意思。

  122. 江边菜鸟
    *.*.*.*
    链接

    江边菜鸟 2009-09-01 18:29:00

    学习了

  123. luojie
    183.16.119.*
    链接

    luojie 2010-08-19 09:54:20

    你好! 看了您关于Windbg调试的博文(找出TestClass.TestMethod方法的“位置”,于是先使用!name2ee命令获得TestClass类的信息),加载完sos.dll后想请问如果是泛型类如何使用!name2ee命令获得泛型类的信息。像这样!name2ee *!namespace.classname不行。烦请解答。 谢谢

  124. nerocool
    58.247.192.*
    链接

    nerocool 2010-09-30 14:20:58

    我想,除非您了解到JIT对待这两个指令的具体方式,否则您是无法得出其中性能高低的。因为IL还是过于高级,您看到了一条IL指令,您可以知道它的作用,但是您还是不知道它最终造成了何种结果。您还是无法证明“Object泛型集合的性能不会低于直接存放Object的非泛型集合”。也正因为如此,我在那篇文章里探究问题的手段,是比较了MyArrayList.getItem方法和MyList.getItem方法的汇编代码,最后得出结果是“毫无二致”。由于汇编代码和机器代码一一对应,因此观察汇编代码就可以完全了解CPU是如何执行这两个方法的。汇编代码一模一样,就意味着CPU对待这两个方法的方式一模一样,它们的性能怎么会有不同呢?

    虽然说根据WinDebug观察到“Object泛型集合”和“Object的非泛型集合”最终生成的汇编代码是一样的,但是中间还是一个关键问题,那就是JIT在编译这两种的集合之间的性能到底怎么样?举个例子:比如说两端代码虽然都生成了同样的汇编代码“aaa”(我这是举例,当然生成的肯定不是这样子),但是JIT编译“Object泛型集合”花了1秒而“Object的非泛型集合”花了0.5秒,您说这两个性能哪个好呢?

  125. 老赵
    admin
    链接

    老赵 2010-09-30 16:15:07

    @nerocool

    首先JIT不会到秒这个数量级别,其次JIT再慢也就执行一次,就不关心了。

  126. xidao
    113.88.6.*
    链接

    xidao 2011-06-21 16:54:43

    @老赵

    我没有接触过il,不过一直想知道,有没有il层的调试器?既不是C#层得高层调试器,也不是机器汇编层的,可以直观的看到每条il指令的执行,也可以单步?

  127. 老赵
    admin
    链接

    老赵 2011-06-21 23:58:05

    @xidao

    我不是很清楚这个东西。

  128. 叶华斌
    122.240.133.*
    链接

    叶华斌 2011-07-20 13:05:26

    老赵太有才了,把看IL代码比喻成看孩子吃苹果,真是风趣幽默,这样一比较我就明白多了...

  129. llllboy
    10.66.192.76, 219.133.0.*
    链接

    llllboy 2013-10-29 11:55:32

    感觉太高深了,看不懂 怎么办 赵老师 = =

  130. Tig
    140.206.88.*
    链接

    Tig 2014-02-02 16:35:13

    久闻赵姐夫英明神武,老生有一事不明,特来请教. 如下: class test{ static int a; } 众所周知,a会被初始化为0,那么a到底在什么地方被初始化为0的呢,我找了下IL,及用windbg查看汇编,也找不到任何线索.....,还请赐教!!!

  131. 老赵
    admin
    链接

    老赵 2014-02-07 15:32:11

    @Tig

    运行时的规定,在堆上分配内存时就直接填0上去了。WinDBG肯定有线索,只是不容易追而已。

发表回复

登录 / 登录并记住我 ,登陆后便可删除或修改已发表的评论 (请注意保留评论内容)

昵称:(必填)

邮箱:(必填,仅用于Gavatar

主页:(可选)

评论内容(大于5个字符):

  1. Your Name yyyy-MM-dd HH:mm:ss

使用Live Messenger联系我