
浅谈CLR的内存分配和回收机制
发布时间:2006-03-03 21:17:48 来源:博客园 网友评论 0 条
相对于C++程序员来说,C#程序员是非常幸运的,至少我们不需要为内存泄漏(Memory Leak)而头疼,不需要负责内存的分配和回收。但这不意味着我们只需要知道new的语法就可以了,作为一个严肃的C#程序员,我们应该对此有所了解,有助于我们编写性能更好的代码。
一、CLR的内存分配机制
.NET Framework 的垃圾回收器管理应用程序的内存分配和释放。每次使用 new 运算符创建对象时,运行库都从托管堆为该对象分配内存。只要托管堆中有地址空间可用,运行库就会继续为新对象分配空间。
但是,内存不是无限大的。
最终,垃圾回收器必须执行回收以释放一些内存。垃圾回收器优化引擎根据正在进行的分配情况确定执行回收的最佳时间。当垃圾回收器执行回收时,它检查托管堆中不再被应用程序使用的对象并执行必要的操作来回收它们占用的内存。
二、CLR的内存回收机制
一般我们在程序中创建的对象大部分都是托管对象,可依靠GC自动进行内存的回收,但是对于封装了非托管资源的对象,就需要我们显式重载object.Finalize()接口来实现非托管资源的释放。
* 析构函数会在编译时会被翻译为protected void Finalize(),这是C#的析构函数的语法
GC在回收对象之前会调用Finalize()来实现非托管资源的释放,不过按照MSDN的说法,Finalize()会导致性能的降低。
“垃圾回收器使用名为“终止队列”的内部结构跟踪具有 Finalize 方法的对象。每次您的应用程序创建具有 Finalize 方法的对象时,垃圾回收器都在终止队列中放置一个指向该对象的项。托管堆中所有需要在垃圾回收器回收其内存之前调用它们的终止代码的对象都在终止队列中含有项。
实现 Finalize 方法或析构函数对性能可能会有负面影响,因此应避免不必要地使用它们。用 Finalize 方法回收对象使用的内存需要至少两次垃圾回收。当垃圾回收器执行回收时,它只回收没有终结器的不可访问对象的内存。这时,它不能回收具有终结器的不可访问对象。它改为将这些对象的项从终止队列中移除并将它们放置在标为准备终止的对象列表中。该列表中的项指向托管堆中准备被调用其终止代码的对象。垃圾回收器为此列表中的对象调用 Finalize 方法,然后,将这些项从列表中移除。后来的垃圾回收将确定终止的对象确实是垃圾,因为标为准备终止对象的列表中的项不再指向它们。在后来的垃圾回收中,实际上回收了对象的内存。” --[MSDN]
更加建议实现Sytem.IDisposable.Dispose()接口,用来实现对非托管资源的释放,这也是.Net Framework中常见的设计模式。那该怎么实现Dispose呢?
1、首先,Dispose接口应该释放自身对象所占用的资源,还应该调用基类的Dispose方法,释放基类部分所占用的资源。
2、前面说过Finalize()会导致性能问题,那么在执行Dispose以后就应该告诉GC不用在调用Finalize()了
当然我们完全可以定义一个MySpace.IClosable.Close(),通过实现这个接口来进行非托管资源的释放,不过这实在没有必要。
一、CLR的内存分配机制
.NET Framework 的垃圾回收器管理应用程序的内存分配和释放。每次使用 new 运算符创建对象时,运行库都从托管堆为该对象分配内存。只要托管堆中有地址空间可用,运行库就会继续为新对象分配空间。
| ... object obj = new object(); ... |
但是,内存不是无限大的。
| public void FillMemory() { ArrayList memory = new ArrayList(); // 输出填充前所占内存大小 Console.WriteLine("used memory:" + GC.GetTotalMemory(false)); for (int i = 0; i < 100000; i++) { memory.Add(new string("foo")); } // 输出填充后所占的内存大小 Console.WriteLine("used memory:" + GC.GetTotalMemory(false)); } |
最终,垃圾回收器必须执行回收以释放一些内存。垃圾回收器优化引擎根据正在进行的分配情况确定执行回收的最佳时间。当垃圾回收器执行回收时,它检查托管堆中不再被应用程序使用的对象并执行必要的操作来回收它们占用的内存。
二、CLR的内存回收机制
一般我们在程序中创建的对象大部分都是托管对象,可依靠GC自动进行内存的回收,但是对于封装了非托管资源的对象,就需要我们显式重载object.Finalize()接口来实现非托管资源的释放。
| using System; using System.IO; public class Foo { private FileStream _stream; public Foo() { _stream = new FileStream(@"c:/foo.txt", FileMode.Open); } // some other operation here... ~Foo() { // release the unmanaged resource _stream.Close(); } } |
* 析构函数会在编译时会被翻译为protected void Finalize(),这是C#的析构函数的语法
GC在回收对象之前会调用Finalize()来实现非托管资源的释放,不过按照MSDN的说法,Finalize()会导致性能的降低。
“垃圾回收器使用名为“终止队列”的内部结构跟踪具有 Finalize 方法的对象。每次您的应用程序创建具有 Finalize 方法的对象时,垃圾回收器都在终止队列中放置一个指向该对象的项。托管堆中所有需要在垃圾回收器回收其内存之前调用它们的终止代码的对象都在终止队列中含有项。
实现 Finalize 方法或析构函数对性能可能会有负面影响,因此应避免不必要地使用它们。用 Finalize 方法回收对象使用的内存需要至少两次垃圾回收。当垃圾回收器执行回收时,它只回收没有终结器的不可访问对象的内存。这时,它不能回收具有终结器的不可访问对象。它改为将这些对象的项从终止队列中移除并将它们放置在标为准备终止的对象列表中。该列表中的项指向托管堆中准备被调用其终止代码的对象。垃圾回收器为此列表中的对象调用 Finalize 方法,然后,将这些项从列表中移除。后来的垃圾回收将确定终止的对象确实是垃圾,因为标为准备终止对象的列表中的项不再指向它们。在后来的垃圾回收中,实际上回收了对象的内存。” --[MSDN]
更加建议实现Sytem.IDisposable.Dispose()接口,用来实现对非托管资源的释放,这也是.Net Framework中常见的设计模式。那该怎么实现Dispose呢?
1、首先,Dispose接口应该释放自身对象所占用的资源,还应该调用基类的Dispose方法,释放基类部分所占用的资源。
| public void Dispose() { // do something to release my unmanaged resource ReleaseMyResource(); base.Dispose(); } |
2、前面说过Finalize()会导致性能问题,那么在执行Dispose以后就应该告诉GC不用在调用Finalize()了
| public void Dispose() { // do something to release my unmanaged resource ReleaseMyResource(); base.Dispose(); // tell gc not to call Finalize() GC.SuppressFinalize(this); } |
当然我们完全可以定义一个MySpace.IClosable.Close(),通过实现这个接口来进行非托管资源的释放,不过这实在没有必要。
全站资源
- 微软官方入门教程19:轻松掌握Vista系统的快
- 微软2008大冲击,预借Vista SP1力促Vista市
- 在收件箱中获得 Windows Vista 的最新更新
- 微软官方Vista入门教程全集19篇(Vista学院
- Windows Vista 的成功将势不可挡
- 快快抛弃Vista,拥抱XP SP3!你觉得呢?
- 浅谈Vista系统关闭虚拟内存与使用内存盘加速
- 嘿嘿,按下键盘上面的三个键,马上让你的Vi
- Windows Vista的盗版率只有Windows XP的一半
- 3DMark和PCMark Vantage新版将只支持Vista系
阅读排行
- .net页面间的参数传递简单实例
- VC++与Matlab混合编程之引擎操作详解
- Oracle数据库数据对象分析
- Eclipse3.2+Tomcat5.5.17+Oracle9配置
- Oracle数据库中索引的维护
- 在Oracle的网络结构中解决连接问题
- Oracle数据安全面面观
- Oracle数据库的ORA-00257故障解决过程
- Oracle数据库备份与恢复的三种方法
- Oracle与SQL Server在企业应用中的比较
最新技术文档
- Oracle中使用自治事务保存日志表条目
- 在Oracle的网络结构中解决连接问题
- Oracle数据库备份与恢复的三种方法
- Oracle 9i 数据库WITH查询语法小议
- Hibernate二级缓存攻略
- Oracle 的数据库的数据备份与恢复
- Oracle 10g的安装步骤和注意事项
- 为AJAX应用程序构建一个错误提交系统
- Atlas快速入门之实战Atlas
- 基于AJAX技术提高搜索引擎排名
专题教程
- 大话G游 专题:手机病毒揭密
- ARP攻击防范与解决方案 路由故障处理手册
- Picasa中文版_Picasa教程 专题:清除流氓软件
- Firefox专题 seo搜索引擎优化专区
- 重装Windows必知的事情 装机之必备软件大行动
病毒专杀栏
