Строки C# (и другой API.NET) ограничены 2 ГБ в размере?

Сегодня я заметил, что Строковый класс C# возвращает длину строки как Интервал. Так как Интервал всегда - 32 бита, независимо от того, что архитектура, это означает, что строка может только составить 2 ГБ или меньше в длине?

Строка на 2 ГБ была бы очень необычна, и представила бы много проблем наряду с ним. Однако большая часть API.NET, кажется, использует 'интервал' для передачи значений, таких как длина и количество. Это означает, что мы навсегда ограничены размерами набора, которые помещаются в 32 бита?

Походит на фундаментальную проблему с API.NET. Я ожидал бы, что вещи как количество и длина будут возвращены через эквивалент 'size_t'.

7
задан Andrew 24 June 2010 в 03:24
поделиться

7 ответов

Похоже на фундаментальную проблему с .NET API ...

Не знаю, зашел бы я так далеко.

Рассмотрим практически любой класс коллекций в .NET. Скорее всего, у него есть свойство Count , которое возвращает int . Это говорит о том, что класс ограничен размером int.MaxValue (2147483647). Это не проблема ; это ограничение - и совершенно разумное в подавляющем большинстве сценариев.

В любом случае, что было бы альтернативой? Есть uint , но он не соответствует требованиям CLS. Тогда есть long ...

Что, если Length вернет long ?

  1. В любом месте, где вы захотите, потребуются дополнительные 32 бита памяти знать длину строки.
  2. Преимущество будет заключаться в следующем: строки могут занимать миллиарды гигабайт оперативной памяти. Ура.

Попытайтесь представить себе ошеломляющую стоимость некоторого кода, подобного этому:

// Lord knows how many characters
string ulysses = GetUlyssesText();

// allocate an entirely new string of roughly equivalent size
string schmulysses = ulysses.Replace("Ulysses", "Schmulysses");

В принципе, если вы думаете о string как о структуре данных, предназначенной для хранения неограниченного количества текста, вы: у меня нереалистичные ожидания. Когда дело доходит до объектов такого размера, возникает сомнение, есть ли у вас вообще необходимость хранить их в памяти (в отличие от жесткого диска).

16
ответ дан 6 December 2019 в 06:49
поделиться

Маловероятно, что вам понадобится хранить более двух миллиардов объектов в одной единственной коллекции. Вы столкнетесь с довольно серьезным снижением производительности при перечислении и поиске, которые являются двумя основными целями коллекций. Если вы имеете дело с таким большим набором данных, вы почти наверняка можете пойти по другому пути, например, разбить вашу единую коллекцию на множество меньших коллекций, которые содержат части всего набора данных, с которыми вы работаете.

Эй, подождите ... у нас уже есть эта концепция - это словарь !

Если вам нужно сохранить, скажем, 5 миллиардов английских строк, используйте этот тип:

Dictionary<string, List<string>> bigStringContainer;

Давайте сделаем так, чтобы строка ключа представляла, скажем, первые два символа строки. Затем напишите метод расширения, подобный этому:

public static string BigStringIndex(this string s)
{
    return String.Concat(s[0], s[1]);
}

, а затем добавьте элементы в bigStringContainer следующим образом:

bigStringContainer[item.BigStringIndex()].Add(item);

и вызовите его в день.(Очевидно, есть более эффективные способы сделать это, но это всего лишь пример)

О, и если вам действительно действительно нужно иметь возможность искать любой произвольный объект по абсолютному индексу, используйте Массив вместо коллекции. Хорошо, да, вы используете некоторую безопасность типов, но вы можете индексировать элементы массива с помощью long .

1
ответ дан 6 December 2019 в 06:49
поделиться

Тот факт, что фреймворк использует Int32 для Count/Length свойств, индексаторов и т.д., является немного красной селедкой. Настоящая проблема заключается в том, что CLR в настоящее время имеет ограничение на максимальный размер объекта в 2 ГБ.

Поэтому строка - или любой другой отдельный объект - никогда не может быть больше 2 ГБ.

Изменять свойство Length типа string на long, ulong или даже BigInteger бессмысленно, так как в любом случае у вас никогда не может быть более 2^30 символов (максимальный размер 2GB и 2 байта на символ. )

Аналогично, из-за ограничения в 2 ГБ единственными массивами, которые могут даже приблизиться к 2^31 элементу, будут массивы bool[] или byte[], которые используют только 1 байт на элемент.

Конечно, ничто не мешает вам создавать свои собственные составные типы, чтобы обойти ограничение в 2 ГБ.

(Обратите внимание, что приведенные выше замечания относятся к текущей реализации Microsoft и вполне могут измениться в будущих выпусках. Я не уверен, что Mono имеет подобные ограничения.)

1
ответ дан 6 December 2019 в 06:49
поделиться

Если вы работаете с файлом размером 2 ГБ, это означает, что вы, вероятно, будете использовать много оперативной памяти и увидите очень низкую производительность.

Вместо этого для очень больших файлов рассмотрите возможность использования MemoryMappedFile (см .: http://msdn.microsoft.com/en-us/library/system.io.memorymappedfiles.memorymappedfile.aspx ). Используя этот метод, вы можете работать с файлом практически неограниченного размера, не загружая все это в память.

-1
ответ дан 6 December 2019 в 06:49
поделиться

При некотором значении String.length(), вероятно, около 5MB, использовать String уже не совсем практично. String оптимизирована для коротких фрагментов текста.

Подумайте о том, что произойдет, если вы сделаете

msString += " more chars"

Что-то вроде:

Система вычисляет длину myString плюс длину " more chars"

Система выделяет это количество памяти

Система копирует myString в новую область памяти

Система копирует " more chars" в новую область памяти после последнего скопированного символа myString

Оригинальная myString остается на милость сборщика мусора.

Хотя это хорошо и аккуратно для маленьких кусочков текста, это кошмар для больших строк, просто найти 2 ГБ непрерывной памяти, вероятно, будет проблемой.

Поэтому, если вы знаете, что будете обрабатывать более нескольких мегабайт символов, используйте один из классов *Buffer.

3
ответ дан 6 December 2019 в 06:49
поделиться

Верно, максимальная длина будет равна размеру Int32, однако вы, скорее всего, столкнетесь с другими проблемами памяти, если все равно имеете дело со строками большего размера.

5
ответ дан 6 December 2019 в 06:49
поделиться

Даже в x64-версиях Windows меня поразил .Net, ограничивающий каждый объект до 2 ГБ.

2 ГБ - это довольно мало для медицинского изображения. 2 ГБ - это даже мало для загружаемого образа Visual Studio.

0
ответ дан 6 December 2019 в 06:49
поделиться