C#中的列表大小限制

Ume*_*mer 20 c# list

这可能看起来很讨厌,但为什么我们在列表中有如此短的对象数限制.

我写了以下代码来测试C#中的列表大小

    List<int> test = new List<int>();            
    long test1 = 0;
    try
    {
        while (true)
        {
            test.Add(1);
            test1++;
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show(test1 + "   |   " + ex.Message);
    }
Run Code Online (Sandbox Code Playgroud)

列表的大小只能是134217728

并不是那么不公平:(如果我想添加对象甚至超过'整数'限制(我的意思是对象数> 2 ^ 32),那么什么是替代方式?

Jon*_*eet 57

A List<int>由一个支持int[].一旦无法分配更大的后备阵列,您将失败 - 请记住:

  • 即使在64位中,CLR中每个对象限制为2GB(编辑:从.NET 4.5开始,对于64位CLR可以避免这种情况 - 请参阅<gcAllowVeryLargeObjects>)
  • 该列表将尝试分配一个大于其立即需要的后备阵列,以便在Add不重新分配的情况下适应以后的请求.
  • 在重新分配期间,旧阵列新阵列必须有足够的总内存.

将后置Capacity阵列设置为接近理论极限的值可能会使您获得比自然增长更高的截止点,但肯定会出现这个限制.

预计会有大约2 29个元素的限制(536,870,912) - 我有点惊讶你没有超过134,217,728.你实际拥有多少记忆?你使用的是什么版本的.NET,以及什么样的架构?(对于32位CLR,每个对象的限制可能是1GB,我无法确定.)

请注意,即使每个对象的限制不是问题,只要你有以上2 31元,你就会有问题解决直接这些元素与List<T>作为索引需要一个int值.

基本上,如果你想要一个包含多个int.MaxValue元素的集合,你需要自己编写,可能使用多个支持数组.您可能希望明确禁止删除和任意插入:)

  • @Umer:文档使得它相当清楚:"List <T>`类是`ArrayList`类的通用等价物.它使用一个大小动态增加的数组来实现`IList <T>`泛型接口需要." 当你说它不是"列表"时 - 这取决于你对"列表"的意思.它不是*链接*列表 - 如果你想要其中一个,你想使用`LinkedList <T>`.`List <T>`和数组之间的主要明显区别是数组总是有一个固定的大小,而`List <T>`可以增长和缩小. (6认同)
  • @JonSkeet:你可能会发现我在64位上试过并打268435456,但在32位上只打了134217728.所以我认为这解释了为什么它比你预期的更早停止Umer的部分原因.第二个提示位于List的源代码中,它告诉我们如果一次添加项目1,则容量将始终为2的幂.因此,插入134217729项将强制容量为2 ^ 28,因此新集合需要2 ^ 30个内存,而仍旧生存旧集合需要2 ^ 29个内存.我留给你看看是否能真正解释一切. (6认同)
  • 从.NET Framework 4.5开始,可以为x64进程启用总大小超过2Gb的阵列.只需将<[gcAllowVeryLargeObjects](http://msdn.microsoft.com/en-us/library/hh285054(v = vs.110).aspx)enabled ="True"/>元素添加到app.config文件的运行时配置中. (3认同)
  • 这种增长和缩小必须适当地涉及重新分配,但从API的角度来看,你仍然处理相同的`List <T>`. (2认同)

Bra*_*ner 6

这是一个由Long而不是整数支持的BigList的令人难以置信的天真(并且未经测试)实现.我在大约5分钟内写了它,它没有实现可数或ilist,但它显示了在其他答案中提到的分区.是的,它在VB中,处理它:)

这需要一些非常认真的工作,并在它实际可用之前进行调整,但它说明了这个想法.

Public Class BigList(Of T)
    Private mInternalLists As List(Of List(Of T))
    Private mPartitionSize As Integer = 1000000

    Private mSize As Long = 0

    Public Sub New()
        mInternalLists = New List(Of List(Of T))
    End Sub

    Public Sub Add(Item As T)
        mSize += 1

        Dim PartitionIndex As Integer = CInt(mSize \ mPartitionSize)

        Dim Partition As List(Of T)
        If mInternalLists.Count < PartitionIndex Then
            Partition = New List(Of T)
            mInternalLists.Add(Partition)
        Else
            Partition = mInternalLists(PartitionIndex)
        End If
        Partition.Add(Item)
    End Sub

    Default Public ReadOnly Property Item(Index As Long) As T
        Get
            Dim PartitionIndex As Integer = CInt(mSize \ mPartitionSize)
            Dim Partition As List(Of T)
            If mInternalLists.Count < PartitionIndex Then
                Throw New IndexOutOfRangeException
            Else
                Partition = mInternalLists(PartitionIndex)
            End If

            Return Partition(CInt(mSize Mod mPartitionSize))
        End Get
    End Property
End Class
Run Code Online (Sandbox Code Playgroud)