CLR专题-垃圾回收理解_垃圾回收的执行过程

CLR的垃圾回收解放了.Net程序员跟踪内存使用情况的压力,在编码的时候无需考虑自己创建的变量应该在什么时候需要销毁,有没有被销毁等问题,也在很大程度上避免了因为程序员的疏忽而产生的内存泄露。

然而,这也并非说明.Net程序员完全不需要考虑内存的使用情况,因为.Net程序员需要知道如何编写可以正确清理资源的代码,避免一个程序不合理的占用过量的内存。


C#是面对对象编程,使用new关键字来申请对象的内存,而这些申请出来的对象正是“垃圾“的来源。垃圾回收,所谓的“垃圾”并不仅仅指过时的变量,还包括了文件、网络连接、数据库等资源,这些资源都会占用一定的内存。

CLR要求所有的资源都从托管堆中分配,在程序启动时,CLR会保留一块连续的地址空间,这个地址空间就是托管堆,托管堆会维护一个指针NextObjPtr,它指向下一个对象在内存中的位置。下图展示了三个对象的托管堆,如果要分配新的对象,它将被放置在NextObjPtr指向的位置。

                                                                                                         

当我们使用new关键字来声明一个对象的时候,会导致编译器在方法的IL代码中生成一个newobj指令,newobj指令将会导致CLR执行以下步骤。

1.计算类型(包含其所有基类型)的字段所需要的字节数。

2.CLR检查托管堆中是否有足够的空间给申请的对象分配内存,如果空间足够,则将对象放入NextObjPtr指向的地址。然后调用类型的实例构造器并返回对象的地址。在地址返回前,NextObjectPtr指针的值会加上对象占据的字节数得到一个新的值,这个值将会指向下一个对象放入托管堆的地址。

但是如果托管堆的内存不足以给新的对象分配空间,CLR就需要执行一次垃圾回收。垃圾回收器会检查托管堆中是否有应用程序不再使用的任何对象。如果有,他们的内存会被回收,如果垃圾回收后堆中仍然没有可用的内存时,就会抛出一个OutOfMemoryException的异常。


那么垃圾回收器是如何知道一个对象不再使用了呢?

每个应用程序在启动后都包含一组root,每个root都是一个指向引用类型对象的指针,这个指针要么指向了托管堆中的一个对象,要么指向了null。而每个root指向的对象,都不应被垃圾回收器回收。

类型中定义的任何静态字段可以被认为是一个root,任何方法的参数、局部变量也可以被认为是一个root。只有引用类型的对象才可以被认为是一个root,值类型永远不会是一个root(思考为什么?)。

在垃圾回收器开始执行回收时,它假设堆中所有的对象都是垃圾,即是线程栈中没有引用堆中的变量,CPU寄存器没有引用堆中的对象,也没有静态字段引用堆中的对象,然后开始回收的第一个阶段,标记

  • 标记

垃圾回收器会沿着线程栈检查所有的root,在每个root指向对象的同步块索引字段上标记一个bit,将其值设为1,同时它会以递归的方式遍历所有可达的对象,为每个对象引用的其他对象进行标记。如果垃圾回收器尝试标记一个已经标记过的对象,则会退出这一次递归。

检查完所有的根之后,程序中就会有一组已标记过的和未标记过的对象,已标记过的对象是程序可达的对象,未标记的对象是程序不可达的。不可达的对象会被认为是需要回收的真正的垃圾,然后垃圾回收器开始第二个阶段,压缩

  • 压缩

在这个阶段,垃圾回收器会线性的遍历堆,寻找没有被标记的连续大内存,忽略小内存块。垃圾回收器会将被标记的对象移动到这些可被复用的内存中以压缩堆的空间,同时负责修改指向这个对象的指针的地址。

很显然,垃圾回收会降低程序的性能,但是得到的好处也是显而易见的。

1.不需要自己实现代码来管理应用程序所用的对象的生存期。

2.避免了内存泄露

3.堆的压缩可以避免内存空间的碎片化。如果是非托管堆,地址空间的碎片化可能会很严重。


注意!

类型的静态字段永远是他引用的的任何对象的root对象,造成内存泄露的一个常见原因是让某个静态字段引用一个集合对象,并且不停的向集合对象中添加数据项,静态字段保持了集合对象的存活,而集合对象则保持了所有数据项的存活,这就造成这些集合中的对象将永远无法被释放。

所以应该尽量避免使用复杂类型的静态字段。

 

 

 

                                                                                                                                                        

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值