如何在C#中截断数组

时间:2015-10-29 16:05:50

标签: c# c++ .net arrays memory-management

我的意思是它真的可能吗? MSDN表示数组是固定大小的,调整大小的唯一方法是#34; copy-to-new-place"。但也许有可能使用内部CLR结构的不安全/一些魔法,它们都是用C ++编写的,我们有一个完整的内存控制,可以调用realloc等等。

我没有为此问题提供代码,因为我甚至不知道它是否可以存在。

我不是在谈论Array.Resize方法等等,因为他们显然没有必要的行为。

假设我们有一个带有2GB ram的标准x86进程,并且我有1.9GB由单个数组填充。然后我想释放一半。所以我想写一些类似的东西:

MagicClass.ResizeArray(ref arr, n)

并且不要获得OutOfMemoryException。 Array.Resize将尝试分配另一千兆字节的RAM,并将失败,1.9 + 1> 2GB OutOfMemory。

3 个答案:

答案 0 :(得分:2)

您可以尝试Array.Resize()

  int[] myArray = new int[] { 1, 2, 3, 4 };
  int myNewSize = 1;

  Array.Resize(ref myArray, myNewSize);

  // Test: 1
  Console.Write(myArray.Length);

答案 1 :(得分:1)

realloc尝试进行inplace resize - 但它保留将整个内容复制到其他位置并返回完全不同的指针的权利。

.NET的List<T>类几乎都暴露了相同的外向行为 - 如果您发现自己经常更改数组大小,那么您应该使用它。它隐藏了您的实际数组引用,以便更改在所有对同一列表的引用中传播。当您从末尾删除项目时,只有列表的长度发生变化,而内部数组保持不变 - 避免复制。

它没有释放内存(您可以随时使用Capacity = XXX明确地执行此操作,但这会生成数组的新副本),但是再次,除非您& #39;重新使用大型数组,realloc也没有 - 如果您正在使用大型阵列,yada,yada - 我们已经在那里:)

realloc在.NET无论如何的内存模型中都没有意义 - 堆随着时间的推移不断收集和压缩。因此,如果您只是在修剪阵列时尝试使用它来避免副本,同时还要保持较低的内存使用率......不要打扰。在下一次堆压缩时,将移动数组上方的整个内存以填充空白。即使可以执行realloc,你只需要复制数组就可以将数组保存在旧生存堆中 - 这不一定是你想要的

答案 2 :(得分:1)

BCL中的数组类型都不支持您想要的内容。话虽这么说 - 你可以实现自己的类型,以支持你所需要的。它可以由标准数组支持,但是会实现自己的Length和indexer属性,这些属性会“隐藏”你的数组部分。

public class MyTruncatableArray<T>
{
    private T[] _array;
    private int _length;

    public MyTruncatableArray(int size)
    {
        _array = new T[size];
        _length = size;
    }

    public T this[int index]
    {
        get
        {
            CheckIndex(index, _length);
            return _array[index];
        }
        set
        {
            CheckIndex(index, _length);
            _array[index] = value;
        }
    }

    public int Length
    {
        get { return _length; }
        set
        {
            CheckIndex(value);
            _length = value;
        }
    }

    private void CheckIndex(int index)
    {
        this.CheckIndex(index, _array.Length);
    }

    private void CheckIndex(int index, int maxValue)
    {
        if (index < 0 || index > maxValue)
        {
            throw new ArgumentException("New array length must be positive and lower or equal to original size");
        }
    }
}

这实际上取决于究竟需要什么。 (例如,您是否需要截断以便您可以更轻松地从代码中使用它。或者是perf / GC /内存消耗是一个问题?如果后者是这种情况 - 您是否执行任何测量证明标准Array.Resize方法无法使用为你的情况?)