温故之.NET内存管理

内存管理:分配、释放与垃圾回收

.NET 内存管理是自动进行的,包括以下几个过程

  • 内存分配
  • 内存释放
  • 代(Generations
  • 非托管资源的内存释放

内存分配

当初始化一个进程时,运行时会为该进程分配一个连续的地址空间区域——即为托管堆。

托管堆就像一个管家一样,始终持有一把钥匙的钥匙(一个指针)——下一个空房间(可用空间首地址,即为下一个对象分配的空间的开始位置)。当然,最开始管家手中的钥匙,是大门的钥匙(即托管堆的基地址)。

所有的引用类型,都是在托管堆上分配的;而值类型的空间则在栈上分配。

需要注意的是:

  1. 引用类型在托管堆上分配空间(房间)之后,对这个空间的引用(钥匙)则是放在栈上(管家手中)的
  2. 对引用(钥匙)的复制,属于简单的复制(浅拷贝)。因为这也仅仅是多了一把钥匙而已,这两把钥匙都只能开同一个房间(两个引用都指向同一个地址空间)

在托管堆中进行内存的分配,还可以带来性能的优势:

  • 运行时为新对象分配内存时,通过不断的更改指针的值(更改管家手中的钥匙),而不是从系统内存中新分配内存(即建造一个新房间)。这样,内存分配的速度几乎可以同在栈上分配一样快了
  • 内存分配的连续性,可以做到快速的访问这些对象

不过,这里有个前提

托管堆中的内存足够应用程序使用。如果不够,运行时将会频繁的进行GC,这会对性能造成很大的影响。比如在Unity3D的开发中,频繁的GC可能会造成游戏画面不连续。

内存的释放

GC会根据对象的分配,来决定该对象回收的最佳时机。

它通过检查应用程序的根来确定不再使用的对象,每个应用程序都有一组根(包含线程堆栈和CPU寄存器上的静态字段、局部变量和参数),每个根要么引用托管堆中的对象,要么被设置为null

GC通过访问JIT和运行时维护的活动根的列表来检查应用程序的根(可访问性检查),同时创建一个可访问的对象图。不在该图中的对象,即表示不可达(无法从根访问),将被GC视为垃圾,并释放为这些对象分配的内存。

在回收过程中,如果发现大量不可访问的对象,则会使用内存复制功能来压缩内存中可访问的对象:移动对象,以保证可访问的对象在一块连续的内存空间内。
同时,对托管堆指针进行更正(重新为管家拿一把钥匙)。这样的好处是,可以让剩下的内存空间连续。

值得注意的是,为了性能,在进行内存复制的时候,将不会处理托管堆中的大型对象(如图像)。
其一,这些大对象的移动可能会花很长时间;
其二,GC的过程中,会挂起正在运行的线程,如果在这过程中去移动这些大对象,则可能会造成程序假死。

代(Generations

为了优化GC性能,托管堆被分为了三代:第0代、第1代和第2代。

其垃圾回收算法的原理如下:

  • 压缩一部分内存要比压缩整个托管堆快
  • 较新的对象的生存期较短,较老的对象的生存期较长
  • 较新的对象与其他对象有更大的关联性,且基本上会在某一时间段内被应用程序访问

鉴于以上原理,有以下的过程:

  1. 新的对象存储在第0
  2. 老的对象如果未被回收,则升级为第1代和第2
  3. GC在第0代已满的时候,将回收第0代中的对象(新对象),而这往往可以回收足够多的内存
  4. 在第0代回收的过程中,未被回收的对象,将会升级为第1
  5. 若第0代的回收中,未能回收到足够的内存,这时,GC将对第1代的对象进行回收
  6. 以此类推,第1代未被回收的,将会升级为第2代,等等。

非托管资源的内存释放

非托管资源与托管资源不同,它们的内存需要我们显式的释放。

其释放方式,除了上一篇文章温故之.NET托管资源与非托管资源中介绍的方式外,还有另外一种方式。
这种方式我们将在下一篇文章【温故之.NET垃圾回收】中一一道来。

小结

每次GC时,做了什么
  • 检索堆上的每个对象
  • 搜索所有当前对象引用以确定堆上的对象是否仍在作用域内
  • 不在作用域内的对象被标记为删除
  • 删除被标记的对象并将内存返回给堆

故堆上的对象越多,代码中的引用数越多,GC就越费时。
另外需要注意的是,每次GC时,其都会挂起当前正在运行的线程,这肯定会对性能有影响,因此需要避免过多的GC

何时触发GC
  • 堆分配时堆上的可用内存不足时触发GC:顺序为第0代、第1代、第2代,具体可见上面【代(Generations)】
  • GC会不时的自动运行(频率因平台而异),此即为“合适的时机”,但第一条中的情况下,一定会运行
  • 手动GC:调用 GC.Collect()GC.Collect(int generation)
  • 操作系统内存不足时,会触发GC

至此,本节内容讲解完毕。欢迎关注公众号【嘿嘿的学习日记】,所有的文章,都会在公众号首发,Thank you~

转载于:https://juejin.im/post/5b2a24796fb9a00e985f2eb1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值