C#内存管理

内容会持续更新,有错误的地方欢迎指正,谢谢!

垃圾回收机制

Mono垃圾回收机制:一般,不需要我们去管GC,然而GC并不是实时性的,所以我们的资源使用完后, GC不会立刻执行清理来释放内存,因为GC不知道我们是否还会使用,所以它就等待,先处理其他的东西,一段时间后,发现这些东西不再用了,才执行清理,释放内存。

所谓垃圾回收,回收的是分配在托管堆上的内存,对于托管堆外的内存,它无能为力。

C#托管堆采取连续内存存储,新创建对象时只需考虑剩下的堆内存是否足够大就成,但一直生成对象而不析构会使托管堆无限增大,怎么维护这样一块连续内存呢?这也就引出了垃圾回收机制。托管堆的大小是特定的。垃圾收集器GC负责当内存不够的时候释放掉垃圾对象,移动仍在使用的对象连成一块连续内存。而这就带来了性能问题,当对象很大的时候,频繁的移动对象会降低性能,所以C#的垃圾收集引入了世代大对象堆小对象堆的概念。

大对象堆主要负责分配大的对象,小对象堆分配小的。对于大对象和小对象区别对待,采取不同灵活的垃圾回收策略,必定比采用同一种策略好。下面我们讨论一下在SOH和LOH不同的垃圾收集策略:

先说一下世代,请注意,物理上并没有世代这个数据结构,它只是逻辑概念。以小对象堆垃圾回收为例来说:当一个对象被创建的时候,它被定义为第0代对象,而经历一次垃圾收集后还存在的对象就被归为第1代对象,同理经过两次或两次以上还存在的对象就可以看成第2代对象。世代是有大小的,对于SOH对象来说,由于每次垃圾回收都会压缩移动对象,所以世代数越大越在堆底。经历一次垃圾回收,对象都会被移入下一个世代的内存空间中。而每次一个世代内存达到其阙值,都会引发垃圾收集器GC回收一次。这么做的好处就是每次垃圾回收器只是回收一个世代的内存,因为有了世代层次,所以减少了对象移动的次数。

以上讨论都是针对SOH,那对LOH呢?移动一个LOH的对象,成本相当大,那怎么确保它的垃圾回收呢?首先从物理上来说,LOH在托管堆的堆底,SOH在其上,逻辑上讲LOH对象都分配在第二世代,垃圾回收之后的LOH对象仍是第二世代,其回收时并不移动仍在使用的对象,只是清除垃圾对象。当一个新LOH对象创建时,它会从堆底遍历寻找LOH中能满足要求的内存,如果没有接着向堆顶创建(这个过程和C运行时工作原理一样,所以也存在相同的弊端,LOH堆内存有可能存在碎片)。此时如果堆顶已经超出阙值,引发垃圾回收器GC回收内存空间。

总结:我们new出一对象时,如果是小对象则会被分在SOH中,如果是大对象则会被分在LOH中,垃圾回收器只会在第0代和第1代中移动对象。

性能问题

由上可得,C#自动垃圾回收是需要付出成本的,而世代和大对象堆/小对象堆这些概念尽可能地降低了这一成本。

C#下非托管资源的处理

垃圾回收器GC只能收集托管堆的内存,但对于堆外内存比如数据库连接。这样就有一个问题:可能会使您的对象在上次引用之后很长时间不能被终结。如果你的对象占用了昂贵或稀少的资源(如一个数据库连接),这是不能被接受的。为了避免无休止地等待垃圾收集器运行,拥有资源的类型应该实现 IDisposable 接口以主动释放资源。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值