本文共 1110 字,大约阅读时间需要 3 分钟。
为什么垃圾回收?
垃圾回收可以让开发人员从内存管理的麻烦中解放出来,在垃圾回收的环境下,内存申请与对象的创建相关联起来了,当这些对象不再有引用时,占用的内存会被释放。垃圾回收器也提供了析构的接口,用来管理不在托管堆上的非托管资源,开发者可以自定义如何在不需要这些资源时的处理方式,两个主要的目标是:
1,去掉内存管理的bug和陷阱。
2,管理内存的效率等于或高于手动管理的效率。
当前市面上的编程语言用的垃圾回收机制主要有两种:
1,空闲列表管理(C/C++用的方式)
2,引用计数回收(.NET用的方式)
空闲列表管理
空闲列表管理是C运行时库的内存管理的基础,同时也是C++内存管理的默认方式,如new和delete关键字。空闲的内存块存储在一个链表里。
空闲列表管理的方式:
1,用空闲列表管理的程序用一个空闲的内存池(用链表组织结构)开始。
2,当申请内存的请求到达时,列表中匹配的内存块会返回。
3,如果空闲列表耗尽,内存管理器会向操作系统申请更多穿闲的内存块添加到链表,或者当申请的内存delete的时候也会这么干。
有以下缺点:
1,申请过程的开销,寻找到一块合适的内存块需要时间。
2,销毁内存的开销,返回内存块到空闲列表需要时间。
3,管理开销,需要通过差分计算和修剪空闲列表来避免内存耗尽,这些工作需要一个单独的线程。
引用计数
引用计数回收器把每个对象用一个int型变量(引用的数量)关联起来,当对象创建时,引用计数加1,程序创建一个新的引用到这个对象时,引用计数加1,当程序移除引用时,引用计数减1,当对象的引用计数为0时,对象会被销毁,内存会被回收。
引用计数的缺点是:
1,管理开销,当对象的引用创建或移除时,对象的引用计数必须更新,这意味着频繁的操作类似赋值(a=b)或给函数传一个引用参数。在多核机器上,这个操作会引起同步竞争,并影响缓存命中率。
2,内存使用,对象的引用计数必须存在内存里。
3,正确性,断了环的对象不能被回收,如果程序不再有一个引用直接引用到两个对象,但是这两个对象都互相引用到对方,这时就会发生内存泄露。COM的文档说需要手动打断环。可能描述的不太清楚,看个图吧:
跟踪垃圾回收
首先是标记阶段,这个阶段将所有仍有引用的对象(称作活跃的对象)区分开来。
然后是清理阶段,回收不再使用的对象占用的内存。
最后是紧缩阶段,让活跃的对象在内存中保持连续。
标记阶段
此阶段中,GC会遍历程序中所有引用的对象的图,为了防止误报和漏报,GC需要一组起始点,做为遍历的起始点,称之为根。
建立根之后,这个阶段中垃圾回收器的干的活就容易理解了。GC将遍历过的对象标记一次且仅一次。
转载地址:http://xllgb.baihongyu.com/