Qual é o comprimento máximo possível de uma string .NET?

239

Qual é a string mais longa que pode ser criada no .NET? Os documentos da Stringturma são silenciosos quanto a essa questão, pelo que pude ver, portanto, uma resposta autorizada pode exigir algum conhecimento de componentes internos. A alteração máxima seria em um sistema de 64 bits?

[Isso é solicitado mais por curiosidade do que por uso prático - não pretendo criar nenhum código que use sequências gigantescas!]

McKenzieG1
fonte

Respostas:

346

O limite teórico pode ser 2.147.483.647, mas o limite prático não chega nem perto disso. Como nenhum objeto em um programa .NET pode ter mais de 2 GB e o tipo de string usa UTF-16 (2 bytes para cada caractere), o melhor que você pode fazer é 1.073.741.823, mas é provável que você nunca consiga alocá-lo. em uma máquina de 32 bits.

Essa é uma daquelas situações em que "se você precisar perguntar, provavelmente está fazendo algo errado".

HitScan
fonte
8
Essa é a resposta correta. É mais provável que você fique sem memória antes de poder alocar o suficiente para esgotar o comprimento da string. Em uma nova inicialização, você pode conseguir uma alocação de 2 GB (com 1 milhão de caracteres) conforme mencionado aqui, mas é tudo.
Stephen Deken
4
Supondo que sua afirmação "nenhum objeto possa ter mais de 2 GB" seja precisa, este é o limite teórico e também o prático - a restrição no comprimento da String seria o tamanho total do objeto, não a capacidade do campo Comprimento.
McKenzieG1
12
Se alguém estiver interessado no valor exato, na minha máquina de 64 bits, são 1.073.741.791 (1024 · 1024 · 1024 - 33) caracteres. Veja também minha pergunta relacionada sobre o tamanho máximo exato debyte[] .
svick
4
Eu fico louco por respostas que contêm explicações curtas, mas profundas.
Mikayil Abdullayev
3
Existe uma opção para permitir que os objetos .NET 4.5 (e posteriores) sejam maiores que 2 GB em máquinas de 64 bits. Verifique aqui
Anderson Matos
72

Com base em meu experimento altamente científico e preciso, ele atinge a minha máquina bem antes de 1.000.000.000 de caracteres. (Ainda estou executando o código abaixo para obter uma identificação melhor).

ATUALIZAÇÃO: Depois de algumas horas, eu desisti. Resultados finais: pode ser muito maior que 100.000.000 caracteres, dados instantaneamente System.OutOfMemoryExceptiona 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
fonte
35
Aplicando uma pesquisa binária aqui provavelmente ajudar a encontrar esta resposta muito mais rápido ...
Mario
49

Como a Lengthpropriedade de System.Stringé um Int32, eu acho que o comprimento máximo seria 2.147.483.647 caracteres ( Int32tamanho máximo ). Se demorasse mais, não seria possível verificar o comprimento, pois isso falharia.

Ryan Farley
fonte
2
@ m.edmondson: Na verdade, não estou convencido. Uma matriz para instâncias também tem LongLengthe um fluxo usa longcomo comprimento. Embora seja uma resposta válida, é uma maneira precisa de medir isso.
Willem Van Onsem
1
Mas os dois primeiros bits são usados ​​para indicação ASCII / não ASCII, como diz este artigo , portanto deve ser 2 ^ 30 = 1 073 741 824
Saito
28

Para quem chega atrasado a esse tópico, pude ver que o "você provavelmente não deveria fazer isso" do hitscan pode fazer com que alguém pergunte o que deve fazer ...

A classe StringBuilder geralmente é uma substituição fácil. Considere uma das classes baseadas em fluxo , principalmente, se seus dados vierem de um arquivo.

O problema s += "stuff"é que ele precisa alocar uma área completamente nova para armazenar os dados e, em seguida, copiar todos os dados antigos para ele, além dos novos itens - CADA E CADA ITERAÇÃO DE LOOP. Portanto, adicionar cinco bytes a 1.000.000 s += "stuff"é extremamente caro. Se o que você deseja é escrever apenas cinco bytes até o final e prosseguir com o programa, escolha uma classe que deixe espaço para crescimento:

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

StringBuilderserá auto-grow dobrando quando é limite é atingido. Então, você verá a dor do crescimento uma vez no início, uma vez em 5.000 bytes, novamente em 10.000, novamente em 20.000. Seqüências anexadas incorrerão na dor a cada iteração de loop.

user922020
fonte
4
Também vale a pena notar que StringBuilder permite que você defina o tamanho inicial. Útil se você souber que vai usar 10.000.000 de entradas com antecedência, permitindo ignorar parte da crise.
Kyle Baran
3
+1 Para ver a pergunta e responder a um bom design. Comparativamente, "este é o tamanho da sua string antes que ela sopre", ao contrário de "se você REALMENTE precisar armazenar muito texto, use isso ..."
StevoInco 26/02/15
8

O comprimento máximo de uma string na minha máquina é 1.073.741.791 .

Veja bem, Strings não são limitadas por números inteiros, como geralmente se acredita.

À parte as restrições de memória, as Strings não podem ter mais de 2 30 ( 1.073.741.824 ) caracteres, pois um limite de 2 GB é imposto pelo Microsoft CLR (Common Language Runtime). 33 a mais do que o meu computador permitiu.

Agora, aqui está algo que você pode experimentar.

Crie um novo aplicativo de console C # no Visual Studio e copie / cole o método principal aqui:

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

}

Meus resultados foram os seguintes:

Teste de corda, de Nicholas John Joseph Taylor

Teoricamente, o C # deve suportar uma sequência de int.MaxValue, mas a memória fica sem memória antes disso.

Este é um teste rápido para restringir os resultados e encontrar o comprimento máximo suportado de uma string.

O teste começa ... agora:

s.Length = 1000000000 em 08/05/2019 12:06

A exceção do tipo 'System.OutOfMemoryException' foi lançada. em 08/05/2019 12:06. Após a dizimação, o valor de Incremento é 100000000.

A exceção do tipo 'System.OutOfMemoryException' foi lançada. em 08/05/2019 12:06. Após a dizimação, o valor de Incremento é 10000000. s.Length = 1010000000 em 08/05/2019 12:06 s.Length = 1020000000 em 08/05/2019 12:06 s.Length = 1030000000 em 08/05/2019 12 O valor do frete é calculado automaticamente pelo Mercado Envios, o prazo de entrega varia de acordo com a forma de envio escolhida e não é de nossa responsabilidade``já que a entrega fica a cargo dos Correios. 08/05/2019 12:06

A exceção do tipo 'System.OutOfMemoryException' foi lançada. em 08/05/2019 12:06. Após a dizimação, o valor de Incremento é 1000000. s.Length = 1071000000 em 08/05/2019 12:06 s.Length = 1072000000 em 08/05/2019 12:06 s.Length = 1073000000 em 08/05/2019 12 : 06

A exceção do tipo 'System.OutOfMemoryException' foi lançada. em 08/05/2019 12:06. Após a dizimação, o valor de Incremento é 100000. s.Length = 1073100000 em 08/05/2019 12:06 s.Length = 1073200000 em 08/05/2019 12:06 s.Length = 1073300000 em 08/05/2019 12 O prazo de entrega é contado a partir da confirmação do pagamento, após a confirmação do pagamento, o prazo de produção é contado a partir da confirmação do pagamento. 08/05/2019 12:06

A exceção do tipo 'System.OutOfMemoryException' foi lançada. em 08/05/2019 12:06. Após a dizimação, o valor de Incremento é 10000. s.Length = 1073710000 em 08/05/2019 12:06 s.Length = 1073720000 em 08/05/2019 12:06 s.Length = 1073730000 em 08/05/2019 12 - 06 s.Length = 1073740000 em 08/05/2019 12:06

A exceção do tipo 'System.OutOfMemoryException' foi lançada. em 08/05/2019 12:06. Após a dizimação, o valor de Incremento é 1000. s.Length = 1073741000 em 08/05/2019 12:06

A exceção do tipo 'System.OutOfMemoryException' foi lançada. em 08/05/2019 12:06. Após a dizimação, o valor de Incremento é 100. s.Length = 1073741100 em 08/05/2019 12:06 s.Length = 1073741200 em 08/05/2019 12:06 s.Length = 1073741300 em 08/05/2019 12 O prazo de entrega é contado no 1o dia útil após a confirmação do pagamento, e o prazo de produção é contado a partir da confirmação do pagamento. 08/05/2019 12:07

A exceção do tipo 'System.OutOfMemoryException' foi lançada. em 08/05/2019 às 12:07. Após a dizimação, o valor de Incremento é 10. s.Length = 1073741710 em 08/05/2019 12:07 s.Length = 1073741720 em 08/05/2019 12:07 s.Length = 1073741730 em 08/05/2019 12 O prazo de entrega é contado no 1o dia útil após a confirmação do pagamento, e o prazo de produção é contado a partir da confirmação do pagamento. O prazo de entrega é contado a partir da confirmação do pagamento, após a confirmação do pagamento.

A exceção do tipo 'System.OutOfMemoryException' foi lançada. em 08/05/2019 às 12:07. Após a dizimação, o valor de Incremento é 1. s.Length = 1073741791 em 08/05/2019 12:07

A exceção do tipo 'System.OutOfMemoryException' foi lançada. em 08/05/2019 às 12:07. Após a dizimação, o valor de Incremento é 0. Teste concluído.

O comprimento máximo de uma sequência é 1073741791.

Pressione qualquer tecla para continuar.

O comprimento máximo de uma string na minha máquina é 1073741791.

Eu apreciaria muito se as pessoas pudessem postar seus resultados como um comentário abaixo.

Será interessante saber se as pessoas obtêm resultados iguais ou diferentes.

WonderWorker
fonte
"Veja bem, Strings não são limitadas por números inteiros, como geralmente se acredita." -> um número inteiro em c # pode ir até 2.147.483.647 e seu resultado é muito próximo (32 bytes a menos) desse valor dividido por dois, o que é lógico, pois todos os caracteres de uma String são armazenados como Unicode em dois bytes. Portanto, mesmo que o limite não seja imposto pelo tamanho do número inteiro, ele é notavelmente próximo dele.
Ben
2

200 megas ... nesse momento, seu aplicativo é interrompido virtualmente, possui cerca de um gig de memória de conjunto de trabalho e o sistema começa a agir como se fosse necessário 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
fonte
5
Não sei se o comportamento que você obteria ao criar apenas uma string realmente grande é o mesmo que você está vendo, alocando várias delas e concatenando.
Casey
2

Como String.Lengthé um número inteiro (que é um apelido para Int32), seu tamanho é limitado a Int32.MaxValuecaracteres unicode. ;-)

VVS
fonte