.NET组件程序设计 第4章 生命周期管理

来源:互联网 发布:oracle大表查询优化 编辑:程序博客网 时间:2024/06/06 11:35

托管堆:

.NET运行时都会预先分配一个特殊内存堆(托管堆)。用于为对象,数据存储分配内存。每次new操作,.NET都从托管堆中分配内存。

托管堆是一长内存空间,由.NET维护一个指向堆中下一个可用地址的指针。当.NET需要new一个新对象,会为之分配空间,并移动指针到下一可用地址。

与传统内存分配模式比,此种方式更快。因为对于非托管环境,内存分配由操作系统完成,每次都通过遍历寻找够大的连续内存块。一段时间后,由于内存碎片的存在,使内存块列表变长,影响性能。

 

传统内存释放模式:

C++中,当基于栈的对象超出范围,由C++调用对象析构函数调。

或者,使用delete操作符,调用其析构函数,释放其内存。

 

.NET垃圾回收机制:

 .NET中,退出作用域并不会马上销毁对象。

 

当JIT编译代码,会更新一个对象图,包含顶级原始应用程序起点等。当new一新对象,该对象图被跟新,并在图中添加创建该对象的对象到该对象的引用。JIT会在每次进入,退出作用域时跟新该对象图。对象图用于表达对象是否被引用。

 

垃圾回收器(GC)被触发(托管堆耗尽或显示调用)时,把对象图每个对象都看为垃圾,从根节点开始往下递归遍历,如果对象可以访问,标记为可到达对象。当垃圾收集器达到一个已标记为可到达对象时,不再继续寻找其他从该对象可到达的对象了。不可到达对象被当做垃圾,通过下移压缩托管堆,用可到达对象覆盖不可到达对象,清除。

 

下移压缩托管堆,变动了可到达对象的地址,使其引用无效,因此,垃圾回收器会修正被移动对象的引用(通过挂起所有应用程序安全线程实现)。

 

(@-@其实更复杂!好多对象。。。对象。。。)

 

对象终结:

.NET对象成为垃圾,对象并不会被告知,只被压缩托管堆覆盖掉。为解决对象占有数据库连接等资源释放,.NET提供了对象终结。

垃圾回收器断定一个对象时垃圾,先检查对象元数据,如实现Finalize()方法,垃圾回收器不销毁该对象,反之标记其为可到达(不会被压缩覆盖),然后将之从原始图移到终结队列中,由单独线程调用终结队列中每个对象的Finalize()方法,完成各自的清理工作。最后,垃圾回收器销毁对象。

 

显式垃圾回收:

GC.Collect()可显示触发垃圾回收器,但不推荐,要花费高额代价。推荐使用确定性终结

 

实现Finalize():

调用该方法的时间是不确定的,可能推迟释放资源的时间。C#中会将析构函数解析为Finalize()方法。

 

确定性终结:

显示告知对象何时不需要。

1.开/闭模式:Open(),Close()方法,显示调用释放对象占有宝贵资源。

2.Dispose()模式:用于销毁对象,除了无需等垃圾回收器清理外,写入代码应等同于Finalize()中。

 

using语句:

要求对象实现IDisposable接口。

 

确定性终结模板:

Dispose(),Finalize()并不互斥。Dispose()未调用,可用Finalize()进行资源清理。另一方面,Dispose()被调用,没必要等Finalize()调用才销毁对象。

 

 

 

原创粉丝点击