复制阵列/列表而不触发GC

时间:2013-04-28 17:28:55

标签: c# .net garbage-collection

我手动将较小的数组复制到一个更大的数组中:

T is constrained to class, new()

为什么会触发GC?是否通过引用分配给新数组?为什么旧数组的旧元素仍然被垃圾收集?第一个循环中的赋值是否真的复制了它们?

public void Resize()
{
    T newArray = new T[oldArray.Length * 2];

    for (int i = 0; i < oldArray.Length; i++)
    {
        newArray[i] = oldArray[i];
    }

    for (int i = oldArray.Length; i < newArray.Length; i++)
    {
        // Assign new elements to the new array
    }

    oldArray = newArray;
}

1 个答案:

答案 0 :(得分:3)

一旦调用new,就会在堆上创建对新对象的引用。分配参考时

oldArray = newArray;

两个引用都指向新对象。如果没有对指向的对象oldArray的引用,则它有资格进行垃圾回收。

reference

释放内存。 垃圾收集器的优化引擎根据正在进行的分配确定执行收集的最佳时间。当垃圾收集器执行集合时,它会释放应用程序不再使用的对象的内存。它通过检查应用程序的根来确定哪些对象不再被使用。每个应用程序都有一组根。每个根指向托管堆上的对象或设置为null。应用程序的根包括全局和静态对象指针,线程堆栈上的局部变量和引用对象参数以及CPU寄存器。垃圾收集器可以访问实时(JIT)编译器和运行时维护的活动根列表。使用此列表,它会检查应用程序的根,并在此过程中创建一个图形,其中包含可从根目录访问的所有对象。 不在图中的对象无法从应用程序的根目录中访问。垃圾收集器认为无法访问的对象是垃圾,并将释放为它们分配的内存。在收集期间,垃圾收集器检查托管堆,查找无法访问的对象占用的地址空间块。当它发现每个无法访问的对象时,它使用内存复制功能来压缩内存中的可到达对象,从而释放分配给无法访问的对象的地址空间块。一旦压缩了可到达对象的内存,垃圾收集器就会进行必要的指针更正,以便应用程序的根指向新位置中的对象。它还将托管堆的指针定位在最后一个可到达对象之后。请注意,仅当集合发现大量无法访问的对象时,才会压缩内存。如果托管堆中的所有对象都在集合中存活,则不需要进行内存压缩。 为了提高性能,运行时为单独的堆中的大对象分配内存。垃圾收集器自动释放大对象的内存。但是,为避免在内存中移动大对象,不会压缩此内存。