.net 内存常见问题
GC 内存常见问题
1. GC 对象的复活
namespace ConsoleApplication2 { public class Resurrection { public int Data; public Resurrection(int data) { this.Data = data; }
// finalizer ~Resurrection() { Program.Instance = this; } } class Program { public static Resurrection Instance; static void Main(string[] args) { Instance = new Resurrection(1);
int gen = -1; gen = GC.GetGeneration(Instance); Instance = null; GC.Collect(); GC.WaitForPendingFinalizers(); //object is alive again,and generation is promoted to 1. gen = GC.GetGeneration(Instance); Console.WriteLine(Instance.Data); Instance = null; GC.Collect(); } } }
1.1 执行Collect, 检查引用,对象引用没有了。
1.2 创建实例时已经在Finalizer表上做了记录,所以我们检查到了对象有Finalizer.
1.3 因为有Finalizer, 我们将记录一道Finalizer2表上。
1.4 在Finalizer2表上有记录,所以不释放内存。并提升代龄
1.5 Collect执行完毕。GC.WaitForPendingFinalizers, 我们将等待Finalizer2表上的Finalizers的执行。
1.6 Finalizer执行后我们的Instance 复活了。
1.7 再一次去除所有的引用。
1.8 执行Collect.检查引用,没问题。
1.9 由于上次已经冲Finalizer表里删除,所有这次没有查到。
1.10 释放内存。
2. 非托管资源的释放。
public class Base : IDisposable { public void Dispose() { this.Dispose(true); // Remove this from the Finalizer list. GC.SuppressFinalize(this); }
protected virtual void Dispose(bool disposing) { if (disposing) { // managed resource } // unmanaged resource }
~Base() { this.Dispose(false); } }
如果finalizer执行过久会影响GC的性能。所以最好是在Using来把资源释放,然后从Finalizer表里移除.
3. 弱引用。
public class Fat { public int Data; public Fat(int data) { this.Data = data; } } class Program { static void Main(string[] args) { Fat oFat = new Fat(1); WeakReference oFatRef = new WeakReference(oFat); oFat = null; if (oFatRef.IsAlive) { Console.WriteLine(((Fat)oFatRef.Target).Data); } GC.Collect(); } }
对于胖对象,通过弱引用,可以是对象有段存活时间,此时可以使用它,但是也可能被在内存不够或强制的时候被回收。
4. GC具体做了哪些工作?
- 在标记阶段找到并创建一个所有存活对象的链表。
- 在重定位阶段更新要压缩对象的引用。应该是移动对象的位置,让内存紧凑的排列。
- 在压缩阶段回收死对象的内存空间,并把存活的对象紧凑的排列,来更有效的使用内存。
一般来说,大对象(>= 85000 byte)不会被压缩,否则会影响性能。但是从.net 4.5.1开始我们可以通过GCSettings.LargeObjectHeapCompactionMode 来压缩大对象。
垃圾回收器通过以下的信息来判断对象是否存活:
- 栈根(stack root).
- 垃圾收集句柄(Garbage collection handles). 由用户或者CLR声明的指向托管对象的句柄对象。
- 静态数据.
在垃圾收集开始前,处理跑GC的线程,所有的托管线程被暂停。具体看下图:

参考资料:
https://msdn.microsoft.com/en-us/library/ee787088(v=vs.110).aspx#what_happens_during_a_garbage_collection
浙公网安备 33010602011771号