以下内容转载自C#与.net面试宝典
1.1IL语言如何在.net下运行
所有.NET程序都必须运行在.NET Framework上,而程序最终均将在CLR(Common Language Runtime)上运行。
.NET程序编译后并不是直接生成机器代码,而是生成中间代码(MSIL)简称IL。
分析:
在.NET框架中,公共语言基础结构使用公共语言规范来绑定不同的语言。
公共类型系统(CTS)包含在公共语言规范中的部分要求不同的语言均需要实现,因此公共语言基础结构允许不同的语言使用.NET框架。
在.NET框架中,所有的语言(C#,VB.NET,Effil.NET等)最后都被转换为了一种通用语言,即微软中间语言(MSIL)。
看一段简单的示例代码,以及第一次编译后生成的MSIL语言的情况。代码如下所示。
static void Main(string[] args) //主程序
{
Console.WriteLine("这是一个MSIL测试程序,Hello Kitty"); //输出一个测试信息
Console.Read();
}
这段代码相当简单,编译它所生成的MSIL代码如下:
//将上面C#代码编译成MSIL代码
.method private hidebysig static void Main(string[] args) cil managed //主程序
{
.entrypoint
.maxstack 8
L_0000: nop
L_0001: ldstr "\u8fd9\u662f\u4e00\u4e2aMSIL\u6d4b\u8bd5\u7a0b\u5e8f\uff0cHello Kitty"
L_0006: call void [mscorlib]System.Console::WriteLine(string)
L_000b: nop
L_000c: call int32 [mscorlib]System.Console::Read()
L_0011: pop
L_0012: ret
}
从理论上来说,IL将消除多年以来业界中不同语言之间的纷争。
在.NET的编码世界中可能出现下面的情况:一部分代码使用C#或VB完成的,另一部分代码使用Effil实现,但是最后所有这些不同语言编写的代码都将被转换为中间语言。这将给程序员提供了极大的灵活性,程序员可以选择自己熟悉的、擅长的语言,并且再也不用为学习不断推出的新语言而烦恼。
注意:MSIL通常简称IL。
总结:
MSIL是将.NET代码转化为机器语言的一个中间过程,它是一种介于高级语言和基于Intel的汇编语言之间的伪汇编语言。
当用户编译一个.NET程序时,编译器将源代码翻译成一组可以有效地转换为本机代码且独立于CPU的指令。
当执行这些指令时,实时(JIT)编译器将它们转化为CPU特定的代码。
由于公共语言运行库支持多种实时编译器,因此同一段MSIL代码可以被不同的编译器实时编译并运行在不同的结构上。
1.2 如何使用实时编译进行代码优化
分析:
实时编译,也就是JIT,具有跨平台的优点,实时编译也保证了在新的硬件技术推出后,原先写的代码可以不需要重新编译就直接享用新的技术带来的优点。 但JIT本身作为一种技术,当然存在执行效率低、第一次启动时间长的缺点。
目前有两种方式可以产生本机的机器代码:实时编译(JIT)和预编译方式(产生Native Image)。
JIT的全称是实时编译(Just-In-Time),程序员掌握JIT工作原理是很有必要的。当需要校调对性能要求很高的代码时,MSIL通常不是最好的做法,JIT优化器会默认地优化程序代码。
使用过ildasm或Reflector工具的程序员会发现在Release和Debug模式下产生的MSIL代码几乎完全相同,但由于使用JIT优化,因此Release模式的代码运行效率会如此迅速。
笔者将通过Native Code(本地代码)来查找系统所做的优化,只有当要调用某个方法时,JIT编译器才会将MSIL的方法体编译为相应的本机机器码,这样做可以优化程序的工作集。首先看一段简单的测试代码:
namespace MyConsole
{
class HelloKitty //定义一个简单类HelloKitty
{
static void Main(string[] args) //主程序
{
Console.WriteLine("这是一个MSIL测试程序,Hello Kitty"); //输出一个测试信息
Console.Read();
}
}
}
下面看一下Debug模式下测试代码的本地代码,如下所示。
//将上面C#代码编译成MSIL代码
namespace MyConsole
{
class HelloKitty //定义一个简单类HelloKitty
{
static void Main(string[] args) //主程序
{
00000000 push ebp
00000001 mov ebp,esp
00000003 push edi
00000004 push esi
00000005 push ebx
00000006 sub esp,30h
00000009 xor eax,eax
0000000b mov dword ptr [ebp-10h],eax
0000000e xor eax,eax
00000010 mov dword ptr [ebp-1Ch],eax
00000013 mov dword ptr [ebp-3Ch],ecx
00000016 cmp dword ptr ds:[009892FCh],0
0000001d je 00000024
0000001f call 764F8F29
00000024 nop
Console.WriteLine("这是一个MSIL测试程序,Hello Kitty"); //输出一个测试信息
00000025 mov ecx,dword ptr ds:[022C2088h]
0000002b call 75BC2280
00000030 nop
Console.Read();
00000031 call 75BC2D14
00000036 nop
}
00000037 nop
00000038 lea esp,[ebp-0Ch]
0000003b pop ebx
0000003c pop esi
0000003d pop edi
0000003e pop ebp
0000003f ret
以下是Release模式下的代码:
namespace MyConsole
{
class HelloKitty //定义一个简单类HelloKitty
{
static void Main(string[] args) //主程序
{
Console.WriteLine("这是一个MSIL测试程序,Hello Kitty"); //输出一个测试信息
00000000 push ebp
00000001 mov ebp,esp
00000003 push eax
00000004 mov dword ptr [ebp-4],ecx
00000007 cmp dword ptr ds:[009992FCh],0
0000000e je 00000015
00000010 call 764E8F29
00000015 mov ecx,dword ptr ds:[022D2088h]
0000001b call 75BB2280
Console.Read();
00000020 call 75BB2D14
00000025 nop
}
00000026 nop
00000027 mov esp,ebp
00000029 pop ebp
0000002a ret
注意:同一段测试代码生成的Release模式下只有25行,而Debug模式下却有37行。Release模式下比Debug模式下小很多,也简洁清晰很多。
在实时编译的过程中,JIT引擎会查找一个包含该类型所有方法存根的数据结构,对于未编译成机器代码的方法,存根会包含一个调用JIT的简单命令,当该方法的实时编译结束后,存根的命令会被替换成一条简单的Jmp指令,使得代码跳转到该方法的机器代码位置。
这样导致整个项目的大小进一步的得到了优化,更能高效的执行本地代码。
总结:
JIT的全称是实时编译(Just-In-Time),描述一种操作的词组,该操作只有在必要时才执行,如实时编译或实时对象激活。
运行时需要代码时,将Microsoft中间语言 (MSIL) 转换为机器码的编译。
1.3 什么是.net中私有程序集?
分析:
程序集(Assembly)是包含编译好的、面向.NET Framework的代码的逻辑单元。
私有程序集是相对简单的一种程序集类型。私有程序集一般附带在某些软件上,并且也只能用于该软件中。
比如,程序员创建本地应用程序项目(或组件),编译后可以生成DLL或EXE类型的私有程序集。
当程序员在其他客户应用程序中使用这类程序集时,只需要添加引用即可进行调用。
当这样的程序集被多个应用程序域使用时,每个应用程序域均需要复制该程序集,通常进程中也将存在该程序集的多个副本。
注意:因为应用程序只能加载位于主执行文件所在文件夹或其子文件夹中的程序集,所以系统可以保证私有程序集不被其他软件使用。
总结:
私有程序集是相对简单的一种程序集类型。
私有程序集一般附带在某些软件上,并且也只能用于该软件中。
当程序员在其他客户应用程序中使用这类程序集时,只需要添加引用即可进行调用。
1.4什么是.net中的共享程序集?
分析:
共享程序集与私有程序集相对,使用共享程序集时需注意一些事项
共享程序集(Shared Assembly),与私有程序集相对,它提供多个应用程序域访问同一个程序集的能力,在内存中只存在该程序集的同一份副本,这种非特定于域的代码共享可以极大地节省占用内存资源。
并且在大多数情况下,共享程序集安装在全局程序集高速缓冲存储器(Global Assembly Cache)中,而不存在于应用程序相关目录下。对共享程序集的引用不会产生文件复制,同时也不会产生额外的副本。
使用共享程序集时需要避免共享程序集命名的冲突,以及共享程序集因版本升级带来的不兼容问题。
解决这类问题常见的办法是创建强命名,或者在全局程序集高速缓冲存储器GAC中安装共享程序集。
注意:共享程序集不能通过简单XCOPY 命令实现部署,而应使用MSI(Microsoft Windows Installer)进行。
总结:
共享程序集提供多个应用程序域访问同一个程序集的能力,在内存中只存在该程序集的同一份副本,这种非特定于域的代码共享可以极大地节省占用内存资源。
1.5 .net程序的开发和运行的基本环境是什么?
开发和运行.net程序都必须安装.NET FrameWork组件,当然也必须安装Visual Studio IDE.
1.6 解决方案下的一个项目是否就代表一个程序集
项目和程序集是两个概念,项目不代表程序集。程序集是一个由类型定义,数据文件和资源文件组成的逻辑集合。每个程序集都包含一个程序集清单,该清单常备附加在某个文件头上,也可以设置单独
1.7 .net的应用程序域是什么?
应用程序域是CLR中提供代码运行范围,错误隔离和安全隔离的逻辑单元,功能类似于操作系统的进程。