在线咨询
微博
网吧论坛
游戏告警
网吧特权
全站搜索
APP下载
开网吧
开网咖
注册
网吧转让
网吧供求
关注微信
网吧联盟论坛
网吧系统
┊
网吧经营
┊
网吧无盘
网吧计费
┊
网吧心声
┊
网咖天下
网吧论坛
┊
网吧专题
┊
网吧游戏
首 页
网吧网咖
天下网咖
网吧无盘
网吧技术
网吧经营
电竞酒店
网吧方案
网吧路由
系统开号
推荐大家使用天下网吧小程序
办理Steam特权,网吧加速器,开号服务
网吧无盘系统开号
网吧管理
网吧政策
网吧经营
网吧热点
网吧配机
网吧装修
网吧转让
网吧观点
网吧系统
技术论坛
网吧系统
无盘技术
软件技术
硬件技术
网络技术
网吧路由
网吧安全
网吧故障
网吧计费
技术论坛
无盘教程
无盘优化
无盘工具
无盘配机
无盘故障
无盘论坛
VLAN方案
无线方案
方案实例
方案分析
装修方案
游戏管理
整体方案
无盘方案
软件方案
网络方案
网吧政策
网吧经营
网吧展示
网吧装修
网吧配机
产品评测
产品导购
最新动态
配机展示
网咖桌椅
网咖经营
电竞网咖
网咖VR
网咖水吧
网咖转型
网咖配机
网咖动态
网咖微信营销
网咖欣赏
路由教程
路由下载
路由脚本
路由经验
路由施工
路由工具
路由论坛
宁夏
浙江
贵州
其它省市
四川
电竞酒店网络
电竞酒店装修
行业动态
电竞酒店管理
电竞酒店系统
推荐网吧
网吧黄页
网吧装修
环境设施
网吧电脑
网吧软件
系统桌面
国外网吧
您现在的位置:
天下网吧
>>
网吧天地
>>
天下码农
>>
微信小程序
>> 正文
.Net中的内存回收机制
2010-12-22
vczx
佚名
【
大
中
小
】
垃圾回收器是用来管理应用程序的内存分配和释放的。在垃圾回收器出现以前,程序员在使用内存时需要向系统申请内存空间。有些语言,例如Visual Basic,可以自动完成向系统申请内存空间的工作。但是在诸如Visual C++的语言中要求程序员在程序代码中申请内存空间。如果程序员在使用了内存之后忘了释放内存,则会引起内存泄漏。但是有了垃圾回收器,程序员就不必关心内存中对象在离开生存期后是否被释放的问题。当一个应用程序在运行的时候,垃圾回收器设置了一个托管堆。托管堆和C语言中的堆向类似,但是程序员不需要从托管堆中释放对象,并且在托管堆中对象的存放是连续的。
每次当开发人员使用 new 运算符创建对象时,运行库都从托管堆为该对象分配内存。新创建的对象被放在上次创建的对象之后。垃圾回收器保存了一个指针,该指针总是指向托管堆中最后一个对象之后的内存空间。当新的对象被产生时,运行库就知道应该将新的对象放在内存的什么地方。同时开发人员应该将相同类型的对象放在一起。例如当开发人员希望向数据库写入数据的时侯,首先需要创建一个连接对象,然后是Command对象,最后是DataSet对象。如果这些对象放在托管堆相邻的区域内,存取它们就非常快。
当垃圾回收器的指针指向托管堆以外的内存空间时,就需要回收内存中的垃圾了。在这个过程中,垃圾回收器首先假设在托管堆中所有的对象都需要被回收。然后它在托管堆中寻找被根对象引用的对象(根对象就是全局,静态或处于活动中的局部变量以及寄存器指向的对象),找到后将它们加入一个有效对象的列表中,并在已经搜索过的对象中寻找是否有对象被新加入的有效对象引用。直到垃圾回收器检查完所有的对象后,就有一份根对象和根对象直接或间接引用了的对象的列表,而其它没有在表中的对象就被从内存中回收。
当对象被加入到托管堆中时,如果它实现了finalize()方法,垃圾回收器会在它的终结列表(Finalization List)中加入一个指向该对象的指针。当该对象被回收时,垃圾回收器会检查终结列表,看是否需要调用对象的finalize()方法。如果有的话,垃圾回收器将指向该对象的指针加入一个完成器队列中,该完成器队列保存了那些准备调用finalize()方法的对象。到了这一步对象还不是真正的垃圾对象。因此垃圾回收器还没有把他们从托管堆中回收。
当对象准备被终结时,另一个垃圾回收器线程会调用在完成器队列中每个对象的finalize()方法。当调用完成后,线程将指针从完成器队列中移出,这样垃圾回收器就知道在下一次回收对象时可以清除被终结的对象了。从上面可以看到垃圾回收机制带来的很大一部分额外工作就是调用finalize()方法,因此在实际编程中开发人员应该避免在类中实现finalize()方法。
对于finalize()方法的另一个问题是开发人员不知道什么时候它将被调用。它不像C++中的析构函数在删除一个对象时被调用。为了解决这个问题,在.Net中提供了一个接口IDisposable。微软建议在实现带有fianlize()方法的类的时侯按照下面的模式定义对象:
public class Class1 : IDisposable
{
public Class1()
{
}
~Class1 ()
{
//垃圾回收器将调用该方法,因此参数需要为false。
Dispose (false);
}
//该方法定义在IDisposable接口中。
public void Dispose ()
{
//该方法由程序调用,在调用该方法之后对象将被终结。
//因为我们不希望垃圾回收器再次终结对象,因此需要从终结列表中去除该对象。
GC.SuppressFinalize (this);
//因为是由程序调用该方法的,因此参数为true。
Dispose (true);
}
//所有与回收相关的工作都由该方法完成
private void Dispose(bool disposing)
{
lock(this) //避免产生线程错误。
{
if (disposing)
{
//需要程序员完成释放对象占用的资源。
}
//对象将被垃圾回收器终结。在这里添加其它和清除对象相关的代码。
}
}
}
现在我们了解了垃圾回收器工作的基本原理,接下来让我们看一看垃圾回收器内部是如何工作的。目前有很多种类型的垃圾回收器。微软实现了一种生存期垃圾回收器(Generational Garbage Collector)。生存期垃圾回收器将内存分为很多个托管堆,每一个托管堆对应一种生存期等级。生存期垃圾回收器遵循着下面的原则:
新生成的对象,其生存期越短;而对象生成时间越长的对象,其生存期也就越长。对于垃圾回收器来说,回收一部分对象总是比回收全部对象要快,因此垃圾回收器对于那些生存期短的对象回收的频率要比生存期长的对象的回收频率高。
.Net中的垃圾回收器中目前有三个生存期等级:0,1和2。0、1、2等级对应的托管堆的初始化大小分别是256K,2M和10M。垃圾回收器在发现改变大小能够提高性能的话,会改变托管堆的大小。例如当应用程序初始化了许多小的对象,并且这些对象会被很快回收的话,垃圾回收器就会将0等级的托管堆变为128K,并且提高回收的频率。如果情况相反,垃圾回收器发现在0等级的托管堆中不能回收很多空间时,就会增加托管堆的大小。
在应用程序初始化的之前,所有等级的托管堆都是空的。当对象被初始化的时候,他们会按照初始化的先后顺序被放入等级为0的托管堆中。在托管堆中对象的存放是连续的,这样使得托管堆存取对象的速度很快,因为托管对不必对内存进行搜索。垃圾回收器中保存了一个指针指向托管堆中最后一个对象之后的内存空间。图一中显示了一个包含四个对象的0等级的托管堆。
图一 包含四个对象的托管堆
当0等级托管堆被对象填满后,例如候程序初始化了新的对象,使0等级托管堆的大小超过了256K,垃圾回收器会检查托管堆中的所有对象,看是否有对象可以回收。当开始回收操作时,如前面提到的,垃圾回收器会找出根节点和根节点直接或间接引用了的对象,然后将这些对象转移到1等级托管堆中,并将0等级托管堆的指针移到最开始的位置以清除所有的对象。同时垃圾回收器会压缩1等级托管堆以保证所有对象之间没有内存空隙。当1等级托管堆满了之后,会将对象转移到2等级的托管堆。
例如在图一之后,垃圾回收器开始回收对象,假定D对象将被回收,同时程序创建了E和F对象。这时候托管堆中的对象如图二所示。
图二 回收对象后的0等级和1等级托管堆
然后程序创建了新的对象G和H,再一次触发了垃圾回收器。对象E将被回收。这时候托管堆中的对象如图三所示。
生存期垃圾回收器的原则也有例外的情况。当对象的大小超过84K时,对象会被放入"大对象区"。大对象区中的对象不会被垃圾回收器回收,也不会被压缩。这样做是为了强制垃圾回收器只能回收小对象以提高程序的性能。
控制垃圾回收器
在.Net框架中提供了很多方法使开发人员能够直接控制垃圾回收器的行为。通过使用GC.Collect()或GC.Collect(int GenerationNumber)开发人员可以强制垃圾回收器对所有等级的托管堆进行回收操作。在大多数的情况下开发人员不需要干涉垃圾回收器的行为,但是有些情况下,例如当程序进行了非常复杂的操作后希望确认内存中的垃圾对象已经被回收,就可以使用上面的方法。另一个方法是GC.WaitForPendingFinalizers(),它可以挂起当前线程,直到处理完成器队列的线程清空该队列为止。
使用垃圾回收器最好的方法就是跟踪程序中定义的对象,在程序不需要它们的时候手动释放它们。例如程序中的一个对象中有一个字符串属性,该属性会占用一定的内存空间。当该属性不再被使用时,开发人员可以在程序中将其设定为null,这样垃圾回收器就可以回收该字符串占用的空间。另外,如果开发人员确定不再使用某个对象时,需要同时确定没有其它对象引用该对象,否则垃圾回收器不会回收该对象。
另外值得一提的是finalize()方法应该在较短的时间内完成,这是因为垃圾回收器给finalize()方法限定了一个时间,如果finalize()方法在规定时间内还没有完成,垃圾回收器会终止运行finalize()方法的线程。在下面这些情况下程序会调用对象的finalize()方法:
0等级垃圾回收器已满
程序调用了执行垃圾回收的方法
公共语言运行库正在卸载一个应用程序域
公共语言运行库正在被卸载
欢迎访问最专业的网吧论坛,无盘论坛,网吧经营,网咖管理,网吧专业论坛
https://bbs.txwb.com
关注天下网吧微信/下载天下网吧APP/天下网吧小程序,一起来超精彩
本文来源:
vczx
作者:佚名
上一篇文章:
深入理解.Net中的内存释放,以及有关的注意事项
下一篇文章:
.NET 3.5新特性
相关文章
win10系统netwsw00.sys文件导致蓝屏的问题
维基解密透露:iPhone 6/6S/7/SE出厂就被植入
ETCP谭龙在首届中国城市停车大会承诺全面开放
Surface Book比拼Book One:微软和保时捷之间
网吧专用one up机械键盘系列
国外网咖案例:瑞典inferno online网咖
教你在一个win8.1屏幕打开多个Metro应用
教你将Xbox one游戏串流到win10电脑
长沙i-ONE爱玩网咖,融入女仆装服务员元素
苹果用户必看!四招教你屏蔽iPhone日历、照片
推荐专题 ┊
更多专题..
网吧卫生
网吧电脑配置
开网吧
网吧键盘
网吧配置
网吧GHOST
ROS
网吧软件故障解决
网众无盘
网吧游戏菜单
网吧活动
网吧优化
网吧精品
网吧新手
声明
声明:本站所发表的文章、评论及图片仅代表作者本人观点,与本站立场无关。若文章侵犯了您的相关权益,请及时与我们联系,我们会及时处理,感谢您对本站的支持!联系邮箱:support@txwb.com,系统开号,技术支持,服务联系QQ:
1175525021
本站所有有注明来源为天下网吧或天下网吧论坛的原创作品,各位转载时请注明来源链接!
天下网吧 网吧天下
推荐文章
网吧语音呼叫哪款好用?体验简约
免费绿色简单的网吧语音呼叫系统,天下网吧会员的经典作品,功能强大,使用简单,上手
解决网吧Steam登陆慢的批处理源码
本批处理是解决Steam登陆慢的问题专门编写。原理是修改hosts文件让相关域……
网吧语音呼叫哪款好用?体验简约绿
解决网吧Steam登陆慢的批处理源码
疫情当下,网吧自救讨论之二:租电
疫情下网吧转让增多,疫情期间接手
洛阳网吧求助信,疫情下的网吧行业
网吧做好系统安全,防盗号三要三不
网吧和电竞酒店使用的系统教程和下
网吧千兆低成本升级方案:2.5G到桌
网吧员工服务态度怎么抓上去,我网
关于WIN10下网吧客户端中文输入法与
最新文章
又是一家疫情期间违规营业的网吧
之前天下网吧注意到相关的新闻并发布了预警内容提醒各位疫情期间请按相关规定操作。……
部分网吧英雄联盟卡顿现象持续,
自从3-31日英雄联盟停机更新维护以来,不少网吧在天下网吧上反映卡顿的问题。天……
又是一家疫情期间违规营业的网吧:负责
部分网吧英雄联盟卡顿现象持续,官方称
2022-04-02日网吧游戏更新信息,敬请关注
web端看图神器viewer.js,修复移动端触
网吧Steam每次启动都提示更新,查找日志
网吧疫情停业的网吧自救方案,有人已经
「韬光养晦」二十多年,Intel发力PC端独
设置网吧Steam节点到ChongQing,实现游
2022-04-01日网吧游戏更新信息,敬请关注
macOS Monterey 12.3.1值得升级吗?MBP
本周热门
本月热门
阅读排行
网吧疫情停业的网吧自救方案,有人
网吧语音呼叫哪款好用?体验简约绿
解决网吧Steam登陆慢的批处理源码
又是一家疫情期间违规营业的网吧:
部分网吧英雄联盟卡顿现象持续,官
2022-04-02日网吧游戏更新信息,敬请
web端看图神器viewer.js,修复移动
网吧Steam每次启动都提示更新,查找
LOL酒桶打野E闪 雷柏VT30电竞
雷柏VH650耳机推荐听大片—八佰
网吧和电竞酒店使用的系统教程和下
最近网吧老被盗号,分享一款工具可
英雄联盟进不去,卡「重新连接」界
带120台以上的大型网吧/电竞酒店游
网吧的英雄联盟掉帧、卡顿,CF卡顿
2022年网咖最常玩的游戏是啥?来看
最近显卡降价了,2060快降到发行价
杨天祥与他的网吧故事——网吧行业
2022年网吧可以用电子身份证了吗?
开网吧一天能赚多少钱的数据分析
网吧员工服务态度怎么抓上去,我网
网吧千兆低成本升级方案:2.5G到桌
网吧和电竞酒店使用的系统教程和下
最近网吧老被盗号,分享一款工具可
英雄联盟进不去,卡「重新连接」界
2022年开网吧服务器电脑配置方案三
自从干了网吧,成了人下人了,见谁
从23个习惯中可以看出你是不是老网
带120台以上的大型网吧/电竞酒店游
网吧的英雄联盟掉帧、卡顿,CF卡顿
正在加载..