Какова максимально возможная длина строки .NET?

239

Какую самую длинную строку можно создать в .NET? StringНасколько мне известно, в документах для класса об этом вопросе ничего не говорится, поэтому для авторитетного ответа могут потребоваться некоторые знания внутренних органов. Изменится ли максимум в 64-битной системе?

[Это спрашивает больше о любопытстве, чем о практическом использовании - я не собираюсь создавать какой-либо код, который использует гигантские строки!]

McKenzieG1
источник

Ответы:

346

Теоретический предел может составлять 2 147 483 647, но практический предел далеко не таков. Поскольку ни один объект в .NET-программе не может быть больше 2 ГБ, а строковый тип использует UTF-16 (2 байта на каждый символ), лучшее, что вы можете сделать, - это 1 073 741 823, но вы вряд ли когда-либо сможете выделить это на 32-битной машине.

Это одна из тех ситуаций, когда «если вам нужно спросить, вы, вероятно, делаете что-то не так».

HitScan
источник
8
Это правильный ответ. У вас больше шансов исчерпать память, прежде чем вы сможете выделить достаточно, чтобы исчерпать длину строки. При новой загрузке вы можете выделить 2 ГБ (с 1 МБ символов), как упомянуто здесь, но это все.
Стивен Декен
4
Предполагая, что ваше утверждение «ни один объект не может превышать 2 ГБ» является точным, это и теоретический, и практический предел - ограничение на длину строки будет общим размером объекта, а не емкостью поля длины.
McKenzieG1,
12
Если кого-то интересует точное значение, на моей 64-битной машине это 1 073 741 791 (1024 · 1024 · 1024 - 33) символов. Смотрите также мой связанный вопрос о точном максимальном размереbyte[] .
svick
4
Я схожу с ума от ответов, которые содержат краткое, но подробное объяснение.
Микаил Абдуллаев
3
Существует возможность разрешить объектам .NET 4.5 (и более поздним версиям) быть больше 2 ГБ на 64-разрядных компьютерах. Проверьте здесь
Андерсон Матос
72

Исходя из моего очень научного и точного эксперимента, он превосходит мою машину задолго до 1 000 000 000 символов. (Я все еще использую приведенный ниже код, чтобы получить лучшее определение).

ОБНОВЛЕНИЕ: Через несколько часов я сдался. Окончательные результаты: может превышать 100 000 000 символов, мгновенно получая System.OutOfMemoryException1 000 000 000 символов.

using System;
using System.Collections.Generic;

public class MyClass
{
    public static void Main()
    {
        int i = 100000000;
        try
        {
            for (i = i; i <= int.MaxValue; i += 5000)
            {
                string value = new string('x', i);
                //WL(i);
            }
        }
        catch (Exception exc)
        {
            WL(i);
            WL(exc);
        }
        WL(i);
        RL();
    }

    #region Helper methods

    private static void WL(object text, params object[] args)
    {
        Console.WriteLine(text.ToString(), args);   
    }

    private static void RL()
    {
        Console.ReadLine(); 
    }

    private static void Break() 
    {
        System.Diagnostics.Debugger.Break();
    }

    #endregion
}
bdukes
источник
35
Применение бинарного поиска здесь, вероятно, поможет вам найти этот ответ намного быстрее ...
Марио
49

Поскольку Lengthсвойство System.Stringis является Int32, я предполагаю, что максимальная длина будет 2147483647 символов (максимальный Int32размер). Если это позволит больше, вы не можете проверить длину, так как это не получится.

Райан Фарли
источник
2
@ m.edmondson: я не уверен, на самом деле. Массив для экземпляров имеет LongLengthтак же и поток использования в longкачестве длины. Хотя это правильный ответ, но это точный способ измерить это.
Виллем Ван Онсем
1
Но первые два бита используются для индикации ASCII / не-ASCII, как говорится в этой статье , поэтому должно быть 2 ^ 30 = 1 073 741 824
Сайто
28

Для тех, кто опаздывает на эту тему поздно, я мог видеть, что из-за хитскана "вы, вероятно, не должны этого делать" кто-то может спросить, что он должен делать ...

Класс StringBuilder часто является легкой заменой. Рассмотрим один из потоковых классов, особенно если ваши данные поступают из файла.

Проблема s += "stuff"заключается в том, что ему нужно выделить совершенно новую область для хранения данных, а затем скопировать в нее все старые данные, а также новый материал - КАЖДУЮ И КАЖДУЮ Итерацию цикла. Таким образом, добавление пяти байтов к 1000000 с s += "stuff"очень дорого. Если вам нужно просто написать пять байтов до конца и продолжить свою программу, вам нужно выбрать класс, который оставляет место для роста:

StringBuilder sb = new StringBuilder(5000);
for (; ; )
    {
        sb.Append("stuff");
    }

StringBuilderбудет автоматически расти при удвоении, когда достигнут предел. Итак, вы увидите боль роста один раз в начале, один раз на 5000 байтов, снова на 10 000, снова на 20 000. Добавление строк будет причинять боль при каждой итерации цикла.

user922020
источник
4
ТАКЖЕ стоит отметить, что StringBuilder позволяет вам установить начальный размер. Полезно, если вы знаете, что будете использовать 10 000 000 записей заранее, что позволит вам игнорировать некоторые сложности.
Кайл Баран
3
+1 За просмотр вопроса и ответ на хороший дизайн. Для сравнения: «это то, насколько большой может быть ваша строка, прежде чем она дует», а не «если вам ДЕЙСТВИТЕЛЬНО нужно хранить много текста, используйте это ...»
StevoInco
8

Максимальная длина строки на моей машине составляет 1 073 741 791 .

Видите ли, строки не ограничены целым числом, как принято считать.

Помимо ограничений памяти, строки не могут содержать более 2 30 ( 1 073 741 824 ) символов, поскольку Microsoft CLR (Common Language Runtime) устанавливает ограничение в 2 ГБ. 33 больше, чем позволил мой компьютер.

Теперь, вот что вы можете попробовать сами.

Создайте новое консольное приложение C # в Visual Studio, а затем скопируйте / вставьте основной метод здесь:

static void Main(string[] args)
{
    Console.WriteLine("String test, by Nicholas John Joseph Taylor");

    Console.WriteLine("\nTheoretically, C# should support a string of int.MaxValue, but we run out of memory before then.");

    Console.WriteLine("\nThis is a quickish test to narrow down results to find the max supported length of a string.");

    Console.WriteLine("\nThe test starts ...now:\n");

    int Length = 0;

    string s = "";

    int Increment = 1000000000; // We know that s string with the length of 1000000000 causes an out of memory exception.

    LoopPoint:

    // Make a string appendage the length of the value of Increment

    StringBuilder StringAppendage = new StringBuilder();

    for (int CharacterPosition = 0; CharacterPosition < Increment; CharacterPosition++)
    {
        StringAppendage.Append("0");

    }

    // Repeatedly append string appendage until an out of memory exception is thrown.

    try
    {
        if (Increment > 0)
            while (Length < int.MaxValue)
            {
                Length += Increment;

                s += StringAppendage.ToString(); // Append string appendage the length of the value of Increment

                Console.WriteLine("s.Length = " + s.Length + " at " + DateTime.Now.ToString("dd/MM/yyyy HH:mm"));

            }

    }
    catch (OutOfMemoryException ex) // Note: Any other exception will crash the program.
    {
        Console.WriteLine("\n" + ex.Message + " at " + DateTime.Now.ToString("dd/MM/yyyy HH:mm") + ".");

        Length -= Increment;

        Increment /= 10;

        Console.WriteLine("After decimation, the value of Increment is " + Increment + ".");

    }
    catch (Exception ex2)
    {
        Console.WriteLine("\n" + ex2.Message + " at " + DateTime.Now.ToString("dd/MM/yyyy HH:mm") + ".");

        Console.WriteLine("Press a key to continue...");

        Console.ReadKey();

    }

    if (Increment > 0)
    {
        goto LoopPoint;

    }

    Console.WriteLine("Test complete.");

    Console.WriteLine("\nThe max length of a string is " + s.Length + ".");

    Console.WriteLine("\nPress any key to continue.");

    Console.ReadKey();

}

Мои результаты были следующими:

Струнный тест, Николас Джон Джозеф Тейлор

Теоретически, C # должен поддерживать строку int.MaxValue, но до этого у нас не хватало памяти.

Это быстрый тест для сужения результатов и определения максимальной поддерживаемой длины строки.

Тест начинается ... сейчас:

s.Length = 1000000000 в 05.08.2009 12:06

Исключение типа 'System.OutOfMemoryException' было сгенерировано. в 08.05.2009 12:06. После прореживания значение инкремента равно 100000000.

Исключение типа 'System.OutOfMemoryException' было сгенерировано. в 08.05.2009 12:06. После децимации значение Приращения равно 10000000. s.Length = 1010000000 в 05.08.2009 12:06 s.Length = 1020000000 в 08.05.2009 12:06 s.Length = 1030000000 в 08.05.2009 12 : 06 s.Length = 1040000000 в 05.08.2009 12:06 s.Length = 1050000000 в 08.05.2009 12:06 s.Length = 1060000000 в 08.05.2009 12:06 s.Length = 1070000000 в 05.08.2009 12:06

Исключение типа 'System.OutOfMemoryException' было сгенерировано. в 08.05.2009 12:06. После децимации значение Приращения равно 1000000. s.Length = 1071000000 в 05.08.2009 12:06 s.Length = 1072000000 в 08.05.2009 12:06 s.Length = 1073000000 в 08.05.2009 12 : 06

Исключение типа 'System.OutOfMemoryException' было сгенерировано. в 08.05.2009 12:06. После децимации значение Приращения равно 100000. s.Length = 1073100000 на 05.08.2009 12:06 s.Length = 1073200000 на 05.05.2009 12:06 s.Length = 1073300000 на 05.05.2009 12 : 06 s.Length = 1073400000 в 05.08.2009, 12:06 s.Length = 1073500000 в 08.05.2009, 12:06 s.Length = 1073600000 в 08.05.2009, 12:06 s.Length = 1073700000 в 05.08.2009 12:06

Исключение типа 'System.OutOfMemoryException' было сгенерировано. в 08.05.2009 12:06. После децимации значение Приращения равно 10000. s.Length = 1073710000 на 05.08.2009 12:06 s.Length = 1073720000 на 05.05.2009 12:06 s.Length = 1073730000 на 05.05.2009 12 : 06 s.Length = 1073740000 в 05.08.2009 12:06

Исключение типа 'System.OutOfMemoryException' было сгенерировано. в 08.05.2009 12:06. После прореживания значение Приращения равно 1000. s.Length = 1073741000 в 05.08.2009 12:06

Исключение типа 'System.OutOfMemoryException' было сгенерировано. в 08.05.2009 12:06. После децимации значение Приращения равно 100. s.Length = 1073741100 в 05.08.2009 12:06 s.Length = 1073741200 в 05.05.2009 12:06 s.Length = 1073741300 в 08.05.2009 12 : 07 s.Length = 1073741400 в 05.08.2009 12:07 s.Length = 1073741500 в 05.05.2009 12:07 s.Length = 1073741600 в 05.05.2009 12:07 s.Length = 1073741700 в 05.08.2009 12:07

Исключение типа 'System.OutOfMemoryException' было сгенерировано. в 08.05.2009 12:07. После децимации значение Приращения равно 10. s.Length = 1073741710 в 05.08.2009 12:07 s.Length = 1073741720 в 05.05.2009 12:07 s.Length = 1073741730 в 08.05.2009 12 : 07 s.Length = 1073741740 в 05.05.2009, 12:07 s.Length = 1073741750 в 08.05.2009, 12:07 s.Length = 1073741760 в 08.05.2009, 12:07 s.Length = 1073741770 в 05.08.2009 12:07 s.Length = 1073741780 в 08.05.2009 12:07 s.Length = 1073741790 в 08.05.2009 12:07

Исключение типа 'System.OutOfMemoryException' было сгенерировано. в 08.05.2009 12:07. После прореживания значение Приращения равно 1. s.Length = 1073741791 в 05.08.2009 12:07

Исключение типа 'System.OutOfMemoryException' было сгенерировано. в 08.05.2009 12:07. После прореживания значение Приращения равно 0. Тест завершен.

Максимальная длина строки 1073741791.

Нажмите любую клавишу для продолжения.

Максимальная длина строки на моей машине составляет 1073741791.

Я был бы очень признателен, если бы люди могли опубликовать свои результаты в виде комментария ниже.

Будет интересно узнать, получают ли люди одинаковые или разные результаты.

Чудотворец
источник
«Видите ли, строки не ограничены целым числом, как принято считать». -> целое число в c # может доходить до 2 147 483 647, и ваш результат очень близок (на 32 байта меньше) к этому значению, деленному на два, что логично, поскольку каждый символ строки хранится как Unicode на двух байтах. Таким образом, даже если ограничение не определяется размером целого числа, оно на удивление близко к нему.
Бен
2

200 мегабайт ... в этот момент ваше приложение переходит в режим виртуальной остановки, у него есть память рабочего набора, и операционная система начинает работать так, как будто вам нужно перезагрузиться.

static void Main(string[] args)
{
    string s = "hello world";
    for(;;)
    {
        s = s + s.Substring(0, s.Length/10);
        Console.WriteLine(s.Length);
    }
}

12
13
14
15
16
17
18
...
158905664
174796230
192275853
211503438
loudej
источник
5
Я не уверен, что поведение, которое вы получите от создания только одной действительно большой строки, совпадает с тем, что вы видите, выделяя кучу их и объединяя.
Кейси
2

Поскольку String.Lengthэто целое число (то есть псевдоним Int32), его размер ограничен Int32.MaxValueсимволами Юникода. ;-)

VVS
источник