Размер строк C # (и других .NET API) ограничен 2 ГБ? - PullRequest
7 голосов
/ 24 июня 2010

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

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

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

Ответы [ 8 ]

16 голосов
/ 24 июня 2010

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

Я не знаю, зайду ли я так далеко.

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

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

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

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

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

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

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

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

5 голосов
/ 24 июня 2010

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

3 голосов
/ 24 июня 2010

При некотором значении String.length (), вероятно, около 5 МБ, использование String более нецелесообразно.Строка оптимизирована для коротких битов текста.

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

msString += " more chars"

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

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

Система выделяет этот объем памяти

Система копирует myString в новую ячейку памяти

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

Исходная строка myString оставлена ​​на усмотрение сборщика мусора.

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

Так что, если вы знаете, что обрабатываете больше, чемочень немногие МБ символов используют один из классов * Buffer.

1 голос
/ 26 июня 2012

В версиях .NET до 4.5 максимальный размер объекта составляет 2 ГБ. Начиная с версии 4.5, вы можете выделять более крупные объекты, если gcAllowVeryLargeObjects включен. Обратите внимание, что ограничение для string не затрагивается, но «массивы» должны также охватывать «списки», поскольку списки поддерживаются массивами.

1 голос
/ 24 июня 2010

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

Таким образом, string - или любой другой отдельный объект - никогда не может превышать 2 ГБ.

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

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

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

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

1 голос
/ 24 июня 2010

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

Привет, секундочку .... у нас уже есть эта концепция - она ​​называется словарь !

Если вам нужно сохранить, скажем, 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);

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

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

0 голосов
/ 24 июня 2010

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

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

0 голосов
/ 24 июня 2010

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...