前言:
本文介绍.Net的垃圾回收器(GC)。垃圾回收是影响.Net应用程序性能的主要机制之一。垃圾回收器使开发人员不用担心内存释放问题。阅读本文,你将知道:
1..Net是如何分配内存的
2.为什么需要垃圾回收
3.垃圾回收的分类,.Net使用的是哪种
4.GC对性能的影响
5.1.并行使用GC会遇到的安全问题
5.2.并行使用GC在垃圾回收各阶段会遇到的安全问题
6.服务器垃圾回收有什么特点
7..Net垃圾回收器的"代"模型
8.CLR是怎么使用GC的
9.自动的非确定终结化:Finalize
10.非自动的确定终结化:Disposable
11.什么是弱引用,什么时候用弱引用
12.System.GC类有哪些公开方法
13.垃圾回收触发器的触发优先级
14.最佳实践
.Net是如何分配内存的
通过指针移动满足应用程序内存分配请求。指针永远指向下一块可用内存。这个指针随着应用程序启动,垃圾回收堆创建而初始化,称之为次对象指针。
为什么需要垃圾回收
垃圾回收器是一个高层次的抽象,它将开发人员从管理内存释放的工作中解救出来。当这些对象不再被应用程序引用时,内存就可以被释放了。
垃圾回收的分类,.Net使用的是哪种
垃圾回收器分成以下3种:
空闲列表管理:它时C运行时库提供的内存管理机制。它是一个确定的内存管理器,需要开发者在认为合适时,进行内存的分配和释放。空闲内存块存储在一个列表中,以进行内存分配,而释放的内存则回到这个链表中。
引用计数垃圾回收:它将每一个对象和一个整数关联起来。当对象创建的时则它的引用计数初始化为1。每当应用程序创建一个该对象的引用时,则这个引用计数就增加1。当引用被应用程序移除时,其引用计数就减少1。当引用计数为0时,则这个对象立即器删除,其内存也将被回收。
追踪垃圾回收:它是CLR、Java虚拟机和其他托管环境使用的垃圾回收机制。追踪垃圾回收在内存占用没有超出阈值之前,一般不会有任何的回收开销。它有3个阶段。
1.标记:垃圾回收器将找到所有仍然被应用程序引用的对象。"只读操作"。
2.清理:垃圾回收器将回收未被引用对象占用的空间。
3.压缩:这个阶段将移动活动对象以保证对象内存的连续性。
GC对性能的影响
标记阶段:
1.当进行一次完整的标记时,垃圾回收器几乎遍历了每一个被引用的对象。
2.在一个多处理器系统中,当垃圾回收器标记时,若对象已被加载到其他处理器的缓存中,会造成缓存失效。
清理与压缩阶段
1.移动对象意味着内存复制,对内存占用多的对象来说,是昂贵的开销。
2.对象被移动之后,所有引用的值必须更新其地址。对于被频繁访问的对象来说,这个分散的内存操作势必造成性能问题。
并行使用GC会遇到的安全问题
垃圾回收器和其他应用程序并发执行可能会产生两类问题:
1.假阴性:一个对象满足垃圾回收的条件,但被标记为活动的。
2.假阳性:一个对象被认为是可回收对象,但它仍然被应用程序所引用。
并行使用GC在垃圾回收各阶段会遇到的安全问题
标记阶段:在对象创建完成之前,已经标记它为未被引用。
清理阶段:
1.对象的复制不是原子操作,复制的过程中可能被更改
2.引用的更新也不是原子操作,应用程序可能部分使用新的引用,部分使用旧的引用。
服务器垃圾回收有什么特点
1.每个处理器都有独立的托管堆。每个处理器线程上的内存分配请求会在该处理器的托管堆上执行。
2.每个处理器都拥有一个垃圾回收线程,每个垃圾回收线程都可以在其对应的托管堆上并行的执行垃圾回收操作。
3.所有应用程序线程都会在垃圾回收的过程中被挂起。保证尽快的结束垃圾回收并恢复应用程序的线程执行。
.Net垃圾回收器的"代"模型
第0代:新创建对象的乐园,对第0代垃圾回收是非常廉价而高效的。
第1代:一次垃圾回收后还存活的对象。
第2代:两次垃圾回收过程后存活的对象。对它进行的垃圾回收,是完成的垃圾回收,是非常昂贵的。100MB的对象,需要30毫秒,相对于第0代慢了几个数量级。
大对象堆:GC不会移动大对象,大于85KB的对象。
CLR是怎么使用GC的
CLR创建了两个垃圾回收线程,一个前台一个后台。后台线程执行第2代对象的垃圾回收,如果监听到第0和1代的对象回收,会挂起线程并交给前台垃圾回收线程调用。
自动的非确定终结化:Finalize
任何对象都可以通过重写System.Object定义的Finalize方法来进行自动化终结。在c#里,它有个更好的名字,叫析构函数。~File
非自动的确定终结化:Disposable
.Net规定所有需要进行确定终结化的对象都必须实现IDisposable接口。
C#中可以使用using块来保证调用Disposable方法,他是对Try...finally的封装。
什么是弱引用,什么时候用弱引用
像一种隐形的"绳索",既能够绑在对象上,又不影响垃圾回收对它的回收。例如:
1.对象存活下使用的外部服务。定时器和事件服务可以为对象所用,但是不需要维持对象的引用。
2.Cpu缓存可以保有最近适用对象的弱引用而不妨碍它们被回收。
3.大对象的引用。如果大对象被回收,就要重新创建大对象。
System.GC类有哪些公开方法
GC.CollectionCount:返回已执行垃圾回收次数
GC.GetTotalMemory:返回垃圾回收堆占用总的内存数,不可以被垃圾回收的内存数量
GC.GetGeneration:返回指定对象所处的代
GC.Collect:执行一次垃圾回收
垃圾回收触发器的触发优先级
1.第0代对象填充。每当应用程序在小对象堆里分配一个新对象时。
2.大对象堆达到阈值。
3.手动调用GC.Collect。
4.操作系统报告内存过低。
5.一个应用程序被卸载。
6.一个进程或者CLR被关闭。
最佳实践
1.临时对象应该是短生存期对象。
2.大对象应该有较长的生存周期。
3.建议尽可能的使用值类型而不是引用类型。
总结
本文介绍了垃圾回收理论、相关机制的实现细节、常见错误和最佳实践。为自己的程序优化内存管理,设计并选择合适的内存管理策略,是非常有必要的。
网友评论