在不触发GC的情况下复制数组/列表

本文关键字:情况下 复制数组 列表 GC | 更新日期: 2023-09-27 18:11:17

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

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;
}

在不触发GC的情况下复制数组/列表

一旦调用new,就在堆上创建了一个对新对象的引用。当你赋值引用

oldArray = newArray;

两个引用都指向新对象。如果不再有对oldArray所指向的对象的引用,则该对象符合垃圾回收的条件。

参考:

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