NET Framework的垃圾回收机制非常复杂,但平时编程不需要了解它的全部细节。事实上,它设计得是如此周到,以至于根本不会妨碍到你。但是,如果对技术细节感兴趣,就继续阅读这个补充内容。
对象内存从托管堆中分配,这是.NET运行时
专门用来存储动态分配对象的区域。每次分配都在堆中划出一定空间 ,而堆内存可能耗尽,或者更有可能的是,一次分配找不到一个足够大的连续空间。如果内存分配失败,就会调用垃圾回收器检查是否存在没人引用的对象,以便回收其内存来 释放出一些堆内存。
基本过程如下所示:
- 找出所有仍然活动的对象。这意味着要从代码中的对象句柄开始,跟踪这些句柄到其他对象。 这个过程会反复进行,直到找出所有活动对象。
- 标记了所有活动对象后,假定其他对象都是垃圾,它们的内存可以回收。
- 移动活动 对象创建最大的连续可用空间。
- 修改活动 对象的句柄,使句柄指向新位置。
可从这个过程理解为什么要使用句柄来引用对象,它不仅使运行时
能跟踪对象正在被谁使用,还使用户不必关心 对象在内存中的确切位置。
上述过程过于简化。垃圾回收是十分昂贵的操作,会对应用程序的性能产生显著影响。所以,没有必要的时候不 应该对整个内存执行回收。Microsoft在设计.NET时观察到一个有趣的现象:越老的对象活的时间可能更长。换言之 ,一方面是许多新对象快速地生灭,而其他较老的对象能活很久。
这就产生 了代
概念。每个动态创建的对象都属于一代
,每一代都在托管堆中有自己的区域。新建的对象是0代;0代满了就不能创建新对象,此时垃圾回收器只对0代进行回收。回收过程中存活下来的对象提升至1代,0代则被清空,以全新面貌迎接新对象。Microsoft注意到0代是对象生灭最频繁的区域,幸存下来的对象可能活得更久。目前,.NET垃圾回收器只支持三代(0,1和2)。 一 般情况下都应该让垃圾回收器自己决定在什么时候对哪一代执行垃圾回收。但如果确定自己的代码产生了大量可回收的对象,可用静态System.GC.Collect
方法强迫执行一次回收。该方法可执行默认回收,也可指定具体回收哪一代。要知道一个对象当前是哪一代,可以调用System.GC.GetGeneration
方法并传递对象引用。
样例代码:
void Main()
{
Test test = new Test();
for (int i = 0; i < 10000000; i++)
{
if(i % 100000 == 0)
{
var resultLevel = System.GC.GetGeneration(test);
var iLevel = System.GC.GetGeneration(i);
var num = System.GC.GetTotalMemory(true);
Console.WriteLine("Result Level : {0}, I Level : {1}, Memery: {2}", resultLevel, iLevel, num);
}
else
{
var r = new long[100000];
test.Result = Add(i);
}
System.GC.Collect();
}
}
public int Add(int n)
{
Random r = new Random();
return r.Next() + n;
}
public class Test
{
public int Result{get;set;}
}
输出
Result Level : 0, I Level : 0, Memery: 1837112
Result Level : 2, I Level : 0, Memery: 2698728
Result Level : 2, I Level : 0, Memery: 2694912
Result Level : 2, I Level : 0, Memery: 2694912
Result Level : 2, I Level : 0, Memery: 2694912
Result Level : 2, I Level : 0, Memery: 2694912
Result Level : 2, I Level : 0, Memery: 2694160
Result Level : 2, I Level : 0, Memery: 2694160
Result Level : 2, I Level : 0, Memery: 2694160
Result Level : 2, I Level : 0, Memery: 2694256
Result Level : 2, I Level : 0, Memery: 2694256
Result Level : 2, I Level : 0, Memery: 2694160
Result Level : 2, I Level : 0, Memery: 2694256
Result Level : 2, I Level : 0, Memery: 2694256
Result Level : 2, I Level : 0, Memery: 2694160
Result Level : 2, I Level : 0, Memery: 2694160
Result Level : 2, I Level : 0, Memery: 2694160
Result Level : 2, I Level : 0, Memery: 2694256
Result Level : 2, I Level : 0, Memery: 2694256