CLR 公共语言运行时
托管执行过程
1.选择编译器
.net中包括c#,vb,vc++等,选择合适编译器
2.编译为 MSIL
编译器将源代码转换为 Microsoft 中间语言 (MSIL) 和计算机系统结构有关
3.将 MSIL 编译为本机代码
根据本机结构编译为本机代码:
方法1:.net提供.net实时(JIT)编译器 :按需编译代码,边运行边编译,性能会有略微影响;
方法2:使用 NGen.exe 的安装时代码生成:预编译,在运行前将整个程序集编译,存储;
4.代码验证
确认代码是否有权访问内存位置;
5.运行代码
JIT编译:编译运行,编译过的方法,不用再编译,可直接使用;
NGen.exe编译:将存储的映像中的入口点作为运行时的入口点,开始运行;
自动内存管理
在运行时管理内存的分配和释放:帮助处理常见内存问题,如:忘记释放对象导致内存泄露、尝试访问已释放对象的内存等;
1.分配内存
初始化时,在内存中保留一个连续的地址空间区域(最初时虚拟内存,并没有对应的物理内存),为托管堆,托管堆中有一个指针最初指向托管堆的基址,每存入对象后根据存入对象的地址和存入对象的长度,更新这个指针使之一直指向下一个可用地址;托管堆将进程隔离,进程之间不会互相访问相同地址;在托管堆中, 连续分配的对象可以确保它们在内存中是连续的。托管堆做了一个相当大胆的假设一地址空间和存储是无限的。这个假设显然是荒谬的。托管堆必须通过某种机制来允许它做这样的假设。这个机制就是垃圾回收器。后面讲述它的工作原理 。
在新建对象时,值类型根据类型字节数分配内存字节数,如int分配4个;引用类型内存分配包括两部分,指针占4个字节,内容是地址或者null,引用类型内容占实际需要字节数加上4字节(32位)方法表指针,4字节(32位)同步索引块,在64位机器上方法表指针和同步所以块各占8位;
引用类型一般被如下的对象引用:
● 栈上的一个变量(最常见的情况)。
● P/Invoke 情形下的句柄表。
● Finalizer queue,即终结队列。
● 寄存器。
如创建下面的User对象需要内存:
public class User
{
public int Age { get; set; }
public string Name { get; set; }
public string _Name = “123” + “abc”;
public List _Names;
public string GetName()
{
Name = _Name;
return Name;
}
}
属性Age值类型Int,4字节;
属性Name,引用类型,初始为NULL,4个字节,指向空地址;
字段_Name初始赋值了,代码会被编译器优化为_Name