明白.net中的垃圾回收机制

https://www.red-gate.com/simple-talk/dotnet/net-framework/understanding-garbage-collection-in-net/

一旦你了解了.NET的垃圾回收器是如何工作的,那么你能清楚的明白一些可能会影响.NET应用程序的神秘问题。.NET虽然声称不用手动进行内存管理,但如果你想避免内存相关的错误和一些性能问题,在开发.NET应用程序时,仍然有必要对内存的使用情况有所了解。

.NET的垃圾回收器已经推出多时,作为Windows应用程序中手动内存管理和内存泄漏的终结者:其想法是,有了垃圾回收器在后台运行,开发人员不再需要担心对象的生命周期管理问题。一旦应用程序使用完对象,垃圾回收器就会对它进行处理。

然而,现实情况比这复杂的多。垃圾回收器不仅仅解决了程序中最常见的内存泄漏问题,那些由于开发人员在使用后忘记释放内存而造成的内存泄漏。而且它还解决了使用中的内存被过早释放的问题。但是,当垃圾回收器对一个对象是否还 "活着 "和是否还需要,有分歧的时候,就会导致出现问题。在解决这些问题之前,你需要对垃圾回收器的工作原理有一定的了解。

垃圾收集器的工作原理

那么,垃圾回收器是如何实现这种魔法的呢?基本思路其实很简单:它检查那些放置在内存中的对象,并通过运行程序中的一系列引用,识别出那些可以 "到达 "的对象。

当垃圾回收开始时,它查看一组称为 "GC Root "的引用。这些引用指向的对象被指定为总是可已“到达“,垃圾回收器会将这些引用指向的对象标记为 "活的",然后沿着引用链条,继续查找这些对象的成员变量所引用的其他对象,并将找到对象也标记为 "活的"。以此类推,不断遍历,直到它无法找到对象为止。

注意:查找一个对象所引用的其他对象时,不仅仅是查找当前对象的成员变量,还查找它的父类的成员变量。

一旦知道了所有这些“活的“”对象,那么任何剩下的对象,都成为可以被丢弃的对象,它们占用的内存空间也将在之后重新分配给新的对象。而且,由于.NET在垃圾回收时会对内存进行压缩,所以并不会产生内存空隙(垃圾回收器会有效的挤出这些丢弃对象占用的内存空间),这意味着空闲的内存总是位于堆的末尾,从而使得分配新对象的速度非常快。

“GG Root" 本身不是一个对象,而是引用(确切的说是引用变量,如引用类型的静态变量,等)。任何引用只要是 CG Root 引用 就会自动的存活到下一次的垃圾回收。这里有四种主要情况,会被认定为 CGRoot 引用。

1.当前正在运行的方法中的一个局部变量被认为是 GC Root。这些变量所引用的对象总是可以被它们所声明的方法立即访问,所以必须保留在周围。这些根的寿命可能取决于程序的构建方式。在调试构建中,只要方法在堆栈上,本地变量就会持续存在。在发布构建中,JIT能够通过查看程序结构来计算出一个变量在执行过程中的最后一点可以被方法使用,并在不再需要它的时候丢弃。这种策略并不总是被使用,可以通过在调试器中运行程序等方式关闭。

2.静态变量也总是被认为是 GC Root。它们引用的对象可以在任何时候被声明它们的类访问(如果它们是公共的,则程序的其他部分也可以访问),所以.NET将始终保留它们。作为 "线程静态 "声明的变量只会在该线程运行时持续存在。

3.如果一个被管理的对象通过interop传递给非管理的COM+库,那么它也会成为一个具有引用计数的 GC Root。这是因为COM+不做垃圾回收。相反,它使用的是一个引用计数系统;一旦COM+库通过将引用计数设置为0来完成对象,那么这个对象就不再是GC根,可以再次被收集。

4.如果一个对象有一个终结器,当垃圾回收器决定它不再是 "活的 "时,它不会立即被删除。相反,在.NET调用了finalizer方法之前,它就会成为一种特殊的根。这意味着,这些对象通常需要不止一次的垃圾收集器才能从内存中移除,因为它们在第一次发现未使用时就会存活下来。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值