Ограничение размера списка в С#
Это может показаться неприятной вещью, чтобы спросить
но почему у нас так короткий предел количества объектов в списке.
Я написал следующий код для проверки размера списка в С#
List<int> test = new List<int>();
long test1 = 0;
try
{
while (true)
{
test.Add(1);
test1++;
}
}
catch (Exception ex)
{
MessageBox.Show(test1 + " | " + ex.Message);
}
и размер списка может быть только 134217728
не так несправедливо:( Что альтернативный путь, если я хочу добавить объекты даже за пределы "целочисленные" (я имею в виду количество объектов > 2 ^ 32)???
Ответы
Ответ 1
A List<int>
поддерживается int[]
. Вы потерпите неудачу, как только больший массив поддержки не может быть выделен - и имейте в виду, что:
- В CLR существует ограничение на 2 ГБ в 64 бит (EDIT: с .NET 4.5 этого можно избежать для 64-битного CLR - см.
<gcAllowVeryLargeObjects>
)
- В списке будет предложено выделить массив поддержки, который больше, чем он требует от него, чтобы разместить последующие запросы
Add
без перераспределения.
- Во время перераспределения должно быть достаточно полной памяти как для старого, так и для нового массива.
Установка Capacity
значения, которое поставит задний массив вблизи теоретического предела, может привести к более высокой точке отсечки, чем естественная роста, но этот предел обязательно придет.
Я ожидал бы предела около 2 29 элементов (536 870 912) - я немного удивлен, что вам не удалось преодолеть 134 217 728. Сколько памяти у вас на самом деле? Какую версию .NET вы используете и какую архитектуру? (Возможно, что ограничение по каждому объекту составляет 1 ГБ для 32-битного CLR, я точно не помню.)
Обратите внимание, что даже если ограничение по каждому объекту не было проблемой, как только вы получили выше 2 31 у вас возникнут проблемы с этими элементами непосредственно с List<T>
, так как indexer принимает значение int
.
В принципе, если вам нужна коллекция с более чем int.MaxValue
элементами, вам нужно будет написать свой собственный, возможно, используя несколько массивов поддержки. Вы можете явно запретить удаление и произвольные вставки:)
Ответ 2
Вот невероятно наивная (и непроверенная) реализация BigList при поддержке Long, а не целого. Я написал его примерно через 5 минут, он не реализует ienumerable или ilist, но показывает Partitioning, о котором упоминалось в других ответах. да, это в 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
Ответ 3
Лимит списков ~ 536 870 912 байтов (1/2 МБ на моей машине (32 бит Win7,.NET 4.0))
Ваши целые числа (по 4 байта), поэтому ограничение ограничено байтом /4 (~ 134 217 727)
Ответ 4
Я не тестировал его, но из-за его реализации LinkedList<T>
должен дать вам возможность добавить больше элементов, чем a List<T>
. Но имейте в виду недостатки (например, вызов Count).