¿Cuál es la longitud máxima posible de una cadena .NET?

239

¿Cuál es la cadena más larga que se puede crear en .NET? Los documentos de la Stringclase no dicen nada sobre esta pregunta, por lo que puedo ver, por lo que una respuesta autorizada puede requerir algunos conocimientos de aspectos internos. ¿Cambiaría el máximo en un sistema de 64 bits?

[Esto se pide más por curiosidad que por uso práctico: ¡no tengo la intención de crear ningún código que use cadenas gigantescas!]

McKenzieG1
fuente

Respuestas:

346

El límite teórico puede ser 2.147.483.647, pero el límite práctico no está cerca de eso. Dado que ningún objeto individual en un programa .NET puede tener más de 2 GB y el tipo de cadena usa UTF-16 (2 bytes para cada carácter), lo mejor que puede hacer es 1,073,741,823, pero es probable que nunca pueda asignar eso en una máquina de 32 bits.

Esta es una de esas situaciones en las que "si tiene que preguntar, probablemente esté haciendo algo mal".

HitScan
fuente
8
Esta es la respuesta correcta. Es más probable que se quede sin memoria antes de poder asignar suficiente para agotar la longitud de la cadena. En un arranque nuevo, es posible que pueda extraer una asignación de 2 GB (con 1 millón de caracteres) como se menciona aquí, pero eso es todo.
Stephen Deken
44
Suponiendo que su afirmación "ningún objeto puede superar los 2 Gb" es precisa, este ES el límite teórico y el práctico: la restricción sobre la longitud de la cadena sería el tamaño total del objeto, no la capacidad del campo Longitud.
McKenzieG1
12
Si alguien está interesado en el valor exacto, en mi máquina de 64 bits son 1,073,741,791 (1024 · 1024 · 1024 - 33) caracteres. Vea también mi pregunta relacionada sobre el tamaño máximo exacto debyte[] .
svick
44
Me vuelvo loco por las respuestas que contienen explicaciones cortas pero profundas.
Mikayil Abdullayev
3
Hay una opción para permitir que los objetos .NET 4.5 (y posteriores) tengan más de 2 GB en máquinas de 64 bits. Mira aquí
Anderson Matos
72

Basado en mi experimento altamente científico y preciso, supera mi máquina mucho antes de 1,000,000,000 de caracteres. (Todavía estoy ejecutando el código a continuación para obtener una mejor identificación).

ACTUALIZACIÓN: Después de unas horas, me he rendido. Resultados finales: puede ser mucho más grande que 100,000,000 caracteres, dado instantáneamente System.OutOfMemoryExceptionen 1,000,000,000 caracteres.

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
fuente
35
Aplicar una búsqueda binaria aquí probablemente te ayudaría a encontrar esta respuesta mucho más rápido ...
Mario
49

Como la Lengthpropiedad de System.Stringes un Int32, supongo que la longitud máxima sería 2.147.483.647 caracteres ( Int32tamaño máximo ). Si permitiera más tiempo, no podría verificar la longitud ya que eso fallaría.

Ryan Farley
fuente
2
@ m.edmondson: en realidad no estoy convencido. Una matriz para instancias también tiene un LongLengthy una secuencia utiliza longcomo longitud. Aunque es una respuesta válida, no es una forma precisa de medir esto.
Willem Van Onsem
1
Pero los primeros dos bits se usan para la indicación ASCII / no ASCII como dice este artículo , por lo que debería ser 2 ^ 30 = 1 073 741 824
Saito
28

Para cualquiera que llegue tarde a este tema, podría ver que "probablemente no deberías hacer eso" de hitscan podría hacer que alguien pregunte qué debería hacer ...

La clase StringBuilder es a menudo un reemplazo fácil. Considere especialmente una de las clases basadas en secuencias , si sus datos provienen de un archivo.

El problema s += "stuff"es que tiene que asignar un área completamente nueva para contener los datos y luego copiar todos los datos antiguos más los nuevos: CADA ITERACIÓN DE LAZO. Por lo tanto, agregar cinco bytes a 1,000,000 s += "stuff"es extremadamente costoso. Si lo que desea es escribir cinco bytes hasta el final y continuar con su programa, debe elegir una clase que deje espacio para crecer:

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

StringBuilderse auto-crecimiento, duplicando cuando de límite es exitosa. Entonces, verá el dolor de crecimiento una vez al inicio, una vez a 5,000 bytes, nuevamente a 10,000, nuevamente a 20,000. Las cadenas anexas generarán el dolor en cada iteración del bucle.

usuario922020
fuente
44
TAMBIÉN vale la pena señalar que StringBuilder le permite establecer el tamaño inicial. Es útil si sabe que va a utilizar 10,000,000 entradas antes de tiempo, lo que le permite ignorar parte de la crisis.
Kyle Baran
3
+1 Por ver a través de la pregunta y responder a un buen diseño. Comparativamente, "así de grande puede ser su cadena antes de que explote", en lugar de "si REALMENTE necesita almacenar mucho texto, use esto ..."
StevoInco
8

La longitud máxima de una cadena en mi máquina es 1,073,741,791 .

Verá, las cadenas no están limitadas por un número entero como se cree comúnmente.

Dejando a un lado las restricciones de memoria, las cadenas no pueden tener más de 2 30 ( 1,073,741,824 ) caracteres, ya que Microsoft CLR (Common Language Runtime) impone un límite de 2 GB. 33 más de lo que me permitió mi computadora.

Ahora, aquí hay algo que puedes probar tú mismo.

Cree una nueva aplicación de consola C # en Visual Studio y luego copie / pegue el método principal aquí:

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();

}

Mis resultados fueron los siguientes:

Prueba de cuerda, por Nicholas John Joseph Taylor

Teóricamente, C # debería admitir una cadena de int.MaxValue, pero nos quedamos sin memoria antes de eso.

Esta es una prueba rápida para reducir los resultados para encontrar la longitud máxima admitida de una cadena.

La prueba comienza ... ahora:

s.Longitud = 1000000000 en 05/08/2019 12:06

Se produjo una excepción del tipo 'System.OutOfMemoryException'. al 08/05/2019 12:06. Después de la aniquilación, el valor de Incremento es 100000000.

Se produjo una excepción del tipo 'System.OutOfMemoryException'. al 08/05/2019 12:06. Después del diezmado, el valor de Incremento es 10000000. s.Longitud = 1010000000 al 05/08/2019 12:06 s.Longitud = 1020000000 a 08/05/2019 12:06 s.Longitud = 1030000000 a 08/05/2019 12 : 06 s.Longitud = 1040000000 a 05/08/2019 12:06 s.Longitud = 1050000000 a 08/05/2019 12:06 s.Longitud = 1060000000 a 08/05/2019 12:06 s.Longitud = 1070000000 a 08/05/2019 12:06

Se produjo una excepción del tipo 'System.OutOfMemoryException'. al 08/05/2019 12:06. Después del diezmado, el valor de Incremento es 1000000. s.Longitud = 1071000000 al 08/05/2019 12:06 s.Longitud = 1072000000 al 08/05/2019 12:06 s.Longitud = 1073000000 al 08/05/2019 12 : 06

Se produjo una excepción del tipo 'System.OutOfMemoryException'. al 08/05/2019 12:06. Después del diezmado, el valor de Incremento es 100000. s.Longitud = 1073100000 al 05/08/2019 12:06 s.Longitud = 1073200000 a 08/05/2019 12:06 s.Longitud = 1073300000 a 08/05/2019 12 : 06 s.Longitud = 1073400000 a 05/08/2019 12:06 s.Longitud = 1073500000 a 08/05/2019 12:06 s.Longitud = 1073600000 a 08/05/2019 12:06 s.Longitud = 1073700000 a 08/05/2019 12:06

Se produjo una excepción del tipo 'System.OutOfMemoryException'. al 08/05/2019 12:06. Después del diezmado, el valor de Incremento es 10000. s.Longitud = 1073710000 al 05/08/2019 12:06 s.Longitud = 1073720000 a 08/05/2019 12:06 s.Longitud = 1073730000 a 08/05/2019 12 : 06 s.Longitud = 1073740000 en 05/08/2019 12:06

Se produjo una excepción del tipo 'System.OutOfMemoryException'. al 08/05/2019 12:06. Después de la aniquilación, el valor de Incremento es 1000. s.Longitud = 1073741000 al 05/08/2019 12:06

Se produjo una excepción del tipo 'System.OutOfMemoryException'. al 08/05/2019 12:06. Después del diezmado, el valor de Incremento es 100. s.Longitud = 1073741100 al 08/05/2019 12:06 s.Longitud = 1073741200 al 08/05/2019 12:06 s.Longitud = 1073741300 al 08/05/2019 12 : 07 s.Longitud = 1073741400 a 08/05/2019 12:07 s.Longitud = 1073741500 a 08/05/2019 12:07 s.Longitud = 1073741600 a 08/05/2019 12:07 s.Longitud = 1073741700 a 08/05/2019 12:07

Se produjo una excepción del tipo 'System.OutOfMemoryException'. al 08/05/2019 12:07. Después del diezmado, el valor de Incremento es 10. s.Longitud = 1073741710 al 05/08/2019 12:07 s.Longitud = 1073741720 al 08/05/2019 12:07 s.Longitud = 1073741730 al 08/05/2019 12 : 07 s.Longitud = 1073741740 a 08/05/2019 12:07 s.Longitud = 1073741750 a 08/05/2019 12:07 s.Longitud = 1073741760 a 08/05/2019 12:07 s.Longitud = 1073741770 a 05/08/2019 12:07 s.Longitud = 1073741780 al 08/05/2019 12:07 s.Longitud = 1073741790 al 08/05/2019 12:07

Se produjo una excepción del tipo 'System.OutOfMemoryException'. al 08/05/2019 12:07. Después de la destrucción, el valor de Incremento es 1. s.Longitud = 1073741791 al 05/08/2019 12:07

Se produjo una excepción del tipo 'System.OutOfMemoryException'. al 08/05/2019 12:07. Después de la aniquilación, el valor de Incremento es 0. Prueba completa.

La longitud máxima de una cadena es 1073741791.

Pulse cualquier tecla para continuar.

La longitud máxima de una cadena en mi máquina es 1073741791.

Apreciaría mucho si las personas pudieran publicar sus resultados como un comentario a continuación.

Será interesante saber si las personas obtienen los mismos o diferentes resultados.

WonderWorker
fuente
"Verá, las cadenas no están limitadas por un número entero como se cree comúnmente". -> un número entero en c # puede ir hasta 2,147,483,647 y su resultado está muy cerca (32 bytes menos) a este valor dividido por dos, lo cual es lógico ya que cada carácter de una Cadena se almacena como Unicode en dos bytes. Entonces, incluso si el límite no está impuesto por el tamaño del número entero, es notablemente cercano a él.
Ben,
2

200 megas ... en ese momento, su aplicación se detiene virtualmente, tiene una memoria de conjunto de trabajo y la o / s comienza a actuar como si tuviera que reiniciar.

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
fuente
55
No estoy seguro de que el comportamiento que obtendrías al crear solo una cadena realmente grande sea el mismo que estás viendo al asignar un montón de ellos y concatenar.
Casey
2

Como String.Lengthes un entero (es un alias para Int32), su tamaño está limitado a Int32.MaxValuecaracteres unicode. ;-)

VVS
fuente