程序员首先是人,不是所有人都是细心的,更何况细心的人也会有粗心的时候,因此经常会出现忘了释放已经使用完的资源,导致资源紧张。有时候是不愿去做这些扫尾的事情,因为觉得他的时间应该是用在更伟大更崇高的事业上面,至于清理垃圾这些鸡毛蒜皮的事实在不值得他一屑。于是就有了垃圾回收机制,既减轻了程序员的负担,也避免了资源的泄漏,一举两得。
首先了解一下对象的整个生命过程:
1.给对象分配内存;
2.调用对象构造器进行初始化;
3.使用资源通过访问对象成员;
4.销毁对象;主要是通过Finalization,Dispose和Close方法
5.释放内存。
垃圾回收会在第1步和第5步发生。在第5步进行垃圾回收比较好理解,第1步是如何触发垃圾回收的呢?第1步包含三个过程:首先根据类型成员所需空间总合,然后加上两个额外开销:类型指针(type object pointer)和同步模块索引(sync block index),32位系统下一般是8bytes,64位则是16bytes,最后就是判断当前托管堆中是否有足够的空间去分配这个对象。当满足时就为对象分配所需要的内存,如果不满足就会触发垃圾回收,如果垃圾回收后依然不满足则抛出内存不足的异常。另外分配内存是连续分配的,而且在同一时间段里分配内存的那些对象一般都有很强的联系,比如FileStream和BinaryWriter,连续分配就会使访问命中率提高,使得性能优化。
关键的问题在于垃圾回收器如何知道哪些对象是垃圾,哪些对象是依然在使用的呢?在CLR中,将那些不再被引用的对象被认为是可以被回收的。但对象之间有时候会存在复杂的调用关系,这个时候就需要寻根溯源,找到源头后,将这一系列的对象都标示为正在使用的,直到遍历完所有的源头,那些没被标示的就可以被认为是垃圾被回收掉。那么源头是什么呢?在CLR中有个根(root)的概念,每个应用程序都有一系列的根,根是一个存储位置,它保存着一个指向引用类型对象的指针。因此局部变量,全局变量,静态变量,方法参数以及指向托管堆中对象的CPU寄存器都是根。显然值类型变量是不会为根的。在标记和回收之后还有一个过程,夯实(compact)。 垃圾回收器扫描托管堆,找到连续的内存块,然后移动未回收的对象到更低的地址, 以得到整块的内存,同时所有的对象引用都将被调整为指向对象新的存储位置。
CLR垃圾回收机制中还有个很重要的概念,代(generation)。其主要目的是提高垃圾回收的性能。一般分为3代:0代,1代和2代。0代是新建对象和从未经过垃圾回收对象的集合,1代则是在0代回收过程中未被回收的对象集合,2代是最后一代,也就是经历至少两次回收风暴后依然坚挺的对象的集合
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。