百度360必应搜狗淘宝本站头条
当前位置:网站首页 > IT知识 > 正文

C#内存分配

liuian 2025-08-01 18:40 62 浏览

一 内存分配

C#中的数据类型分为值类型 (Value type) 和引用类型(reference type)。


值 类 型: 所有的值类型都集成自 System.ValueType 上,除非加声明?否则不可为null,保存在 栈(Stack,先进后出)上,常见的值类型有:整形、浮点型、bool、枚举等。


引用类型:所有引用类型都继承自System.Object 上,引用类型保存在 托管堆Heap上,常见的类型有:数组、字符串、接口、委托、object等。


拆箱和装箱:引用类型和值类型的相互转换叫做拆装箱操作。


拆箱:拆箱就是将一个引用型对象转换成任意值型!比如:


int i=0;

System.Object obj=i;

int j=(int)obj;

装箱:装箱就是隐式的将一个值型转换为引用型对象。比如:


int i=0;

Syste.Object obj=i;

二 垃圾回收机制 GC

1 托管资源与非托管资源


GC自动垃圾回收主要是指保存在Heap上的资源,.NET的GC机制有这样两个问题:

 1) GC并不是能释放所有的资源。它不能自动释放非托管资源。

 2) GC并不是实时性的,这将会造成系统性能上的瓶颈和不确定性。

  GC并不是实时性的,这会造成系统性能上的瓶颈和不确定性。所以有了IDisposable接口,IDisposable接口定义了Dispose方法,这个方法用来供程序员显式调用以释放非托管资源。使用using语句可以简化资源管理。


  托管资源 :托管资源指的是.NET可以自动进行回收的资源,主要是指托管堆上分配的内存资源。托管资源的回收工作是不需要人工干预的,有.NET运行库在合适调用垃圾回收器进行回收。


  非托管资源:非托管资源指的是.NET不知道如何回收的资源,最常见的一类非托管资源是包装操作系统资源的对象,例如文件,窗口,网络连接,数据库连接,画刷,图标 等。这类资源,


垃圾回收器在清理的时候会调用Object.Finalize()方法。默认情况下,方法是空的,对于非托管对象,需要在此方法中编写回收非托管资源的代码,以便垃圾回收器正确回收资源。


总结:托管资源是释放由GC来完成,不一定马上回收,一般是系统感觉内存吃紧,会进行紧急回收资源。一个对象想成为被回收,首先需要成为垃圾,GC是通过判断对象及其子对象有没有指向有效的引用,如果没有,GC就认为它是垃圾。垃圾回收机制通过一定的算法得到哪些没有被被引用、或者不再调用的资源,当这些垃圾达到一定的数量时,回启动垃圾回收机制,GC回收实际上是调用了析构函数。

2 垃圾回收算法

大多数CLI使用的是generational, compacting, mark-and-sweep的回收算法:

generational : 经历过垃圾回收且存活下来的对象,更晚地被清理掉。

compacting : 将被回收的对象会被压缩到一起,确保没有脏空间。使用压缩机制使得新对象能快的实例化,而不需要搜索内存找分配空间,同时降低了分页的概率,因为同一页能存储更多对象。另外,垃圾回收会考虑到机器资源,当计算机内存余量较大时很少清理资源。

mark-and-sweep : 每次执行辣鸡回收的时候,都会标记出将要回收的对象。

垃圾回收时对象一共有三代 :0,1,2。每一代都有自己的内存预算,空间不足的时候会调用垃圾回收。为了提高性能都是按代回收,第0代超预算之后就回收第0代的对象,而存活下来的对象就提升为第1代,依次类推,而往往经过多次0代的垃圾回收才能回收一次第1代。

GC进行垃圾回收是系统决定的,下面是进行强制回收的执行代码(非特殊情况下不要使用此方法,会影响系统效率,削弱垃圾回收器中优化引擎的作用,而垃圾回收器可以确定运行垃圾回收的最佳时间)

//对所有代进行垃圾回收。

GC.Collect();

//对指定的代进行垃圾回收。

GC.Collect(int generation);

//强制在 System.GCCollectionMode 值所指定的时间对零代到指定代进行垃圾回收。

GC.Collect(int generation, GCCollectionMode mode);

3 非托管资源的释放

定义一个类时,可以使用两种不同的机制类释放非托管资源,这两种机制有时候放在一起使用。

1)声明析构函数(终结器),作为类的成员

构造函数可以在创建对象实例的时候执行某些操作,析构函数正好相反是资源创建以后被系统回收的时候执行的操作,垃圾回收器在回收对象之前会调用析构函数,所以在函数代码块中可以写释放非托管资源的代码。析构函数没有返回值,没有参数,没有修饰符。

public class AA

{

~AA()

{

//析构函数语法

}

}

析构函数会被编辑器翻译成下面的代码:


protected override void Finalize()

{

try

{

// Cleanup statements...

}

finally

{

base.Finalize();

}

}

最终析构函数会被翻译成上面的代码块,重写基类的Finalize()方法,然后最终调用 Base.Finalize()方法。

注意!大量的使用析构函数会影响效率!带有析构函数的对象会被系统执行两次才会被释放掉。GC执行释放资源时,没有析构函数的资源会被直接释放掉,假如目标对象有析构函数,会被先放进一个叫做“终结队列”的

项中去,然后系统调用另一个高优先级线程来执行 Finalize()方法,GC继续回收其它对象。等方法执行完以后会将对象从终结队列中清除出去,此时对象才是真正意义上的垃圾。等GC执行资源回收的时候,才回释放掉终结队列里面的对象。

总结:

托管堆中内存的释放和析构函数的执行分别属于两个不同的线程。

带有析构函数的对象其生命周期会变长,由上知会进行两次垃圾回收处理才能被释放,如此一来将导致程序性能的下降。

若一个对象引用了其他对象时,当此对象不能够被释放时,则其引用对象也就无法进行内存的释放,也就意味着带有析构函数的对象和其引用对象将从第0代提升到第一代,毫无疑问将影响程序的性能。

综上所述,建议是不要实现其析构函数,这将大大降低程序的性能。

2、在类中实现 System.IDisposable 接口

实现IDisposable接口来显示释放系统资源

① 当我们显示调用Dispose()方法以后,会执行释放费托管资源的操作,然后disposedValue会为Flase,所以我们多次调用也没有关系。Dispose()调用执行完以后,执行GC.SuppressFinalize(this)(告诉GC不再执行终结器操作) 代码

② 如果我们不调用 Diapose()方法,系统会调用使用终结器操作,最后也是释放非托管资源。

从例子可以看出,对于手动回收(disposing为true),除了非托管资源,还可以通知其他托管对象Dispose(),因为这时候内部的托管对象肯定没回收。而到了自动回收,就不能通知其他托管对象了,因为垃圾回收可能已经把他们回收了,而且垃圾回收会自动回收他们,也不用你通知了。

总结:

当释放非托管资源时我们应该显式的去实现Dipose()方法或者Close()方法,但是万一我们忘记显式去调用方法,此时还有一条退路,CLR会自动调用Finalize()方法,很显然调用Finalize()方法会大大降低程序的性能,没关系,上述释放模式关键的一点是通过手动释放调用Dispose()方法可以阻止Finalize()方法的调用,换言之,上述通过手动释放既释放了非托管资源又加快了程序运行的速度,毫无疑问,这是一种完美的解决方案。

1、Finalize是系统决定执行的,我们无法干涉。Dispose是可以我们调用来释放的。

2、Finalize只能释放非托管资源,Dispose既可以释放托管资源也可以释放非托管资源。

相关推荐

tplink无线路由器桥接教程(tplink路由器如何进行无线桥接)

步骤1:将扩展路由器插电源,不要插网线。步骤2:看易展路由器底部标签的SSID,打开手机的wifi设置,搜索这个wifi信号步骤3:链接上易展路由器的wifi信号步骤4:进入设置界面,部分手机可以自动...

怎样还原电脑原来的系统(咋样还原电脑系统)

首先,我们必须确保打开系统还原,否则无法恢复操作系统。在确保已打开的情况下,单击菜单,选择“附件”,点系统工具,并还原系统。接下来,打开系统还原,找到系统还原点,找到最佳适合系统还原的时间点,但确保系...

惠普服务中心电话(孚惠教育退费服务中心电话)

百脑汇里有两家鸿鹄的店面,电话分别是85133339/88609104

win7装xp怎么装系统(windows7装xp)

Windows7和WindowsXP是两个不同的操作系统。但是安装的方法是相同的。第1种就是用安装盘。放入光驱以后。设置启动项以光驱优先,重启电脑,安装光盘,自动引导,按照提示一步一步的就可以安装...

磁盘不相邻怎么扩展卷(磁盘分区不相邻)

要扩展不相邻的磁盘,可以使用磁盘扩展技术,如磁盘阵列(RD)或逻辑卷管理(LVM)。RAID可以将多个磁盘组合成一个逻辑卷,提供更大的存储空间。LVM允许将多个物理卷组合成一个逻辑卷组,并在其中创建逻...

cad2018永久激活密钥(cad 2018激活)

1、首先打开未激活的CAD软件,点击输入序列号。2、选择我同意后进入下一步。然后再点击界面右下角的激活。3、然后输入序列号:666-69696969和产品密钥:001J1。4、然后在界面内点选选择&#...

文件管理应用(文件管理应用同意怎么设置)

推荐文件极客App,免费下载,无广告无内购,功能强大。文件极客app是一款强大的本地、网络文件、iCloud文件共享管理专家,专注于iOS文件一体化管理。在文件极客里面,我们可以通过简单的拖动操作...

ghost64下载(ghost64下载)

方法/步骤分步阅读1/4登陆账号首先进入AppStore,然后登陆美区id账号。2/4搜索点击顶部的搜索栏进入搜索页面。3/4查找结果在搜索结果中找到theghost,点击进入详情页面。4/4下载安...

一般家庭买什么电脑好(不懂电脑的人建议买联想吗)

家庭在使用电脑时,要根据自己的需求来选择电脑。目前电脑主要有两种,一种是笔记本,一种是台式机。1、如果是经常出门办公,比如经常出差需要带电脑,作为家庭在选择电脑时,这时由于自己经常出差带电脑,就要选择...

云电脑软件哪个好用(云电脑好用的)

达龙云电脑在网络环境良好的情况下,操作起来非常流畅。另外,延迟也不高,这点因该说云电脑控制的非常好。云电脑还支持移动设备,安卓、IOS平台都得到了支持。玩家们可以通过在手机端连接云电脑之后就能在手机上...

如何设置网络连接(如何设置网络连接人数)
  • 如何设置网络连接(如何设置网络连接人数)
  • 如何设置网络连接(如何设置网络连接人数)
  • 如何设置网络连接(如何设置网络连接人数)
  • 如何设置网络连接(如何设置网络连接人数)
笔记本电脑如何连接无线wifi

要连接笔记本电脑到WiFi,首先确保你的笔记本电脑有无线网卡,并且WiFi已经开启。在电脑桌面右下角的WiFi图标处点击鼠标右键,选择“打开网络和Internet设置”,然后点击“WiFi”,在可用网...

gho文件安装win10系统方法(gho文件怎么重装系统)

不建议这么操作,如果真的要复制,也是很麻烦的,首先要删除win10里面所有的驱动,注意是所有的,然后关机,注意不能重启进入系统,否则又要重新再来,其次找个U盘pe启动盘或者启动光盘,在开机进入pe系统...

下载163免费邮箱(免费下载网易邮箱163)

第一步:首先,我们手机里要有一个浏览器,小编比较用UC浏览器,当然可以用手机都是自带网页浏览器的,我这边的手机下载网易邮箱第二步:打开UC浏览器或者带浏览器,我们在地址栏上直接输入最新网易邮箱下载安装...

windows microsoft(windows microsoft store加载不出)

电脑开机时出现MicrosoftWindows遇到意外错误,可以尝试用最后一次正确配置来恢复一下。1、重启电脑。2、在电脑显示完硬件信息之后,进入windows界面之前,按F8键。3、在出现的选项菜单...