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


239

Яка найдовша рядок, яку можна створити в .NET? StringНаскільки я бачу, документи для класу мовчать на це питання, тому для авторитетної відповіді може знадобитися деяке знання внутрішніх справ. Максимальна зміна в 64-бітній системі?

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

Відповіді:


346

Теоретична межа може бути 2,147,483,647, але практична межа ніде не наближається до цього. Оскільки жоден об’єкт у програмі .NET може бути більше 2 Гб, а тип рядка використовує UTF-16 (2 байти на кожен символ), найкраще, що ви могли зробити, це 1,073,741,823, але ви, швидше за все, не зможете виділити це на 32-розрядній машині.

Це одна з тих ситуацій, коли "Якщо ти повинен запитати, ти, мабуть, робиш щось не так".


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.OutOfMemoryExceptionв 1 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
}

35
Застосування двійкового пошуку тут, ймовірно, допоможе вам знайти цю відповідь набагато швидше ...
Маріо

49

Оскільки Lengthвластивістю System.Stringє Int32, я б припустив, що максимальна довжина буде 2,147,483,647 символів (максимальний Int32розмір). Якщо це дозволило довше, ви не можете перевірити довжину, оскільки це не вдасться.


2
@ m.edmondson: Я фактично не переконаний. Масив для примірників має LongLengthтак само і потік використання в longякості довжини. Незважаючи на те, що це правильна відповідь, це не точно спосіб вимірювання цього.
Віллем Ван Онсем

1
Але перші два біти використовуються для вказівки ASCII / non-ASCII, як зазначено в цій статті , тому має бути 2 ^ 30 = 1 073 741 824
Сайто

28

Для тих, хто запізнюється на цю тему пізно, я міг бачити, що "скажемо, що ти, мабуть, не повинен робити", хтось може запитати, що їм робити ...

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

Проблема s += "stuff"полягає в тому, що він повинен виділити абсолютно нову область для зберігання даних, а потім скопіювати в неї всі старі дані плюс новий матеріал - ВСЕ ТА КОЖНА ІНТЕРАЦІЯ ЛОПІВ. Отже, додавання п’яти байтів до 1 000 000 за допомогою s += "stuff"надзвичайно дорого. Якщо ви хочете просто написати п'ять байтів до кінця і продовжити свою програму, вам потрібно вибрати клас, який залишає деякий простір для зростання:

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

StringBuilderбуде автоматично зростати за рахунок подвоєння , коли це межа хіт. Отже, ви побачите біль у зростанні один раз на старті, раз у 5000 байт, знову в 10 000, знову в 20 000. Приєднання струн спричинить біль при кожній ітерації петлі.


4
ТАКОЖ варто відзначити, що StringBuilder дозволяє встановити початковий розмір. Корисно, якщо ви знаєте, що ви будете використовувати 10 000 000 записів достроково, що дозволяє ігнорувати деякі проблеми.
Кайл Баран

3
+1 Для перегляду питання та відповіді на гарний дизайн. Порівняно, "це наскільки велика може бути ваша струна до того, як вона почне", на відміну від "якщо вам дійсно потрібно зберігати багато тексту, використовуйте це ..."
StevoInco

8

Максимальна довжина струни на моїй машині - 1,073,741,791 .

Розумієте, рядки не обмежені цілим числом, як прийнято вважати.

Окрім обмежень на пам'ять, рядки не можуть містити більше 2 30 ( 1,073,741,824 ) символів, оскільки обмеження на 2 Гб накладається CLR Microsoft (Загальна мова виконання). На 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.2019 12:06

Виняток типу "System.OutOfMemoryException" було кинуто. на 05.05.2019 12:06. Після децимації значення приросту становить 100000000.

Виняток типу "System.OutOfMemoryException" було кинуто. на 05.05.2019 12:06. Після децимації значення приросту становить 10000000. s.Length = 1010000000 на 05.089 12:06 s.Length = 1020000000 на 05.08.2019 12:06 s.Length = 1030000000 на 05.08.2019 12 : 06 s.Length = 1040000000 в 08.08.2019 12:06 s.Length = 1050000000 в 08.08.2019 12:06 s.Length = 1060000000 в 08.08.2019 12:06 s.Length = 1070000000 в 05.08.2019 12:06

Виняток типу "System.OutOfMemoryException" було кинуто. на 05.05.2019 12:06. Після децимації значення приросту становить 1000000. s.Length = 1071000000 на 05.08.2019 12:06 s.Length = 1072000000 на 05.08.2019 12:06 s.Length = 1073000000 на 05.08.2019 12 : 06

Виняток типу "System.OutOfMemoryException" було кинуто. на 05.05.2019 12:06. Після децимації значення приросту становить 100000. s.Length = 1073100000 на 05.08.2019 12:06 s.Length = 1073200000 на 05.08.2019 12:06 s.Length = 1073300000 на 05.08.2019 12 : 06 s.Length = 1073400000 за 08.08.2019 12:06 s.Length = 1073500000 за 08.08.2019 12:06 s.Length = 1073600000 за 05.08.2019 12:06 s.Length = 1073700000 при 05.08.2019 12:06

Виняток типу "System.OutOfMemoryException" було кинуто. на 05.05.2019 12:06. Після децимації значення приросту становить 10000. s.Length = 1073710000 на 05.08.2019 12:06 s.Length = 1073720000 на 05.08.2019 12:06 s.Length = 1073730000 на 05.08.2019 12 : 06 s.Length = 1073740000 в 05.08.2019 12:06

Виняток типу "System.OutOfMemoryException" було кинуто. на 05.05.2019 12:06. Після децимації значення приросту становить 1000. s.Length = 1073741000 на 05.08.2019 12:06

Виняток типу "System.OutOfMemoryException" було кинуто. на 05.05.2019 12:06. Після децимації значення приросту становить 100. s.Length = 1073741100 на 05.08.2019 12:06 s.Length = 1073741200 на 05.08.2019 12:06 s.Length = 1073741300 на 05.08.2019 12 : 07 s.Length = 1073741400 на 05.08.2019 12:07 s.Length = 1073741500 на 05.08.2019 12:07 s.Length = 1073741600 на 05.08.2019 12:07 s.Length = 1073741700 при 05.08.2019 12:07

Виняток типу "System.OutOfMemoryException" було кинуто. на 05.08.2019 12:07. Після децимації значення приросту становить 10. s.Length = 1073741710 на 05.08.2019 12:07 s.Length = 1073741720 на 05.08.2019 12:07 s.Length = 1073741730 на 05.08.2019 12 : 07 s.Length = 1073741740 в 08.08.2019 12:07 s.Length = 1073741750 в 08.08.2019 12:07 s.Length = 1073741760 в 08.08.2019 12:07 s.Length = 1073741770 при 05.08.2019 12:07 s.Length = 1073741780 на 05.089 12:07 s.Length = 1073741790 на 05.08.2019 12:07

Виняток типу "System.OutOfMemoryException" було кинуто. на 05.08.2019 12:07. Після децимації значення приросту становить 1. s.Length = 1073741791 на 05.08.2019 12:07

Виняток типу "System.OutOfMemoryException" було кинуто. на 05.08.2019 12:07. Після децимації значення приросту дорівнює 0. Тест завершено.

Максимальна довжина рядка - 1073741791.

Натисніть будь-яку кнопку, щоб продовжити.

Максимальна довжина струни на моїй машині - 1073741791.

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

Буде цікаво дізнатися, чи отримують люди однакові чи різні результати.


"Розумієте, рядки не обмежені цілим числом, як прийнято вважати." -> ціле число в c # може перевищувати 2,147,483,647, і ваш результат дуже близький (на 32 байти менше) до цього значення, розділеного на два, що логічно, оскільки кожен символ рядка зберігається як Unicode на два байти. Тож навіть якщо обмеження не накладається розміром цілого числа, воно надзвичайно близько до нього.
Бен

2

200 мегів ... у цей момент ваш додаток перемикається на віртуальну зупинку, має близько пам’яті робочого набору, і o / s починає діяти так, як вам потрібно перезавантажити.

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

5
Я не впевнений, що поведінка, яку ви отримаєте від створення лише однієї дійсно великої струни, така сама, як ви бачите, виділяючи купу їх і об'єднуючись.
Кейсі

2

Оскільки String.Lengthце ціле число (тобто псевдонім для Int32), його розмір обмежений Int32.MaxValueсимволами unicode. ;-)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.