Quelle est la longueur maximale possible d'une chaîne .NET?


239

Quelle est la plus longue chaîne pouvant être créée dans .NET? Les documents de la Stringclasse sont muets sur cette question pour autant que je puisse voir, donc une réponse faisant autorité pourrait nécessiter une certaine connaissance des internes. Le changement maximum sur un système 64 bits?

[Ceci est demandé plus par curiosité que pour une utilisation pratique - je n'ai pas l'intention de créer un code qui utilise des chaînes gigantesques!]

Réponses:


346

La limite théorique peut être de 2 147 483 647, mais la limite pratique est loin de là. Étant donné qu'aucun objet unique dans un programme .NET ne peut dépasser 2 Go et que le type de chaîne utilise UTF-16 (2 octets pour chaque caractère), le mieux que vous puissiez faire est de 1 073 741 823, mais il est peu probable que vous puissiez jamais allouer cela. sur une machine 32 bits.

C'est une de ces situations où "Si vous devez demander, vous faites probablement quelque chose de mal".


8
Ceci est la bonne réponse. Vous êtes plus susceptible de manquer de mémoire avant de pouvoir allouer suffisamment pour épuiser la longueur de la chaîne. Sur un nouveau démarrage, vous pourrez peut-être tirer une allocation de 2 Go (avec 1 million de caractères) comme mentionné ici, mais c'est tout.
Stephen Deken

4
En supposant que votre affirmation «aucun objet ne peut dépasser 2 Go» est exacte, il s'agit de la limite théorique ainsi que de la pratique - la contrainte sur la longueur de la chaîne serait la taille totale de l'objet, pas la capacité du champ Longueur.
McKenzieG1

12
Si quelqu'un est intéressé par la valeur exacte, sur ma machine 64 bits, il s'agit de 1 073 741 791 (1024 · 1024 · 1024 - 33) caractères. Voir aussi ma question connexe sur la taille maximale exacte debyte[] .
svick

4
Je deviens fou de réponses qui contiennent des explications courtes mais détaillées.
Mikayil Abdullayev

3
Il existe une option pour autoriser les objets .NET 4.5 (et versions ultérieures) à dépasser 2 Go sur les machines 64 bits. Vérifiez ici
Anderson Matos

72

Sur la base de mon expérience hautement scientifique et précise, il dépasse ma machine bien avant 1 000 000 000 de caractères. (J'exécute toujours le code ci-dessous pour obtenir un meilleur repérage).

MISE À JOUR: Après quelques heures, j'ai abandonné. Résultats finaux: peut aller bien au-delà de 100 000 000 caractères, instantanément donné System.OutOfMemoryExceptionà 1 000 000 000 caractères.

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
L'application d'une recherche binaire ici vous aiderait probablement à trouver cette réponse beaucoup plus rapidement ...
Mario

49

Étant donné que la Lengthpropriété de System.Stringest un Int32, je suppose que la longueur maximale serait de 2 147 483 647 caractères ( Int32taille maximale ). Si cela permettait plus longtemps, vous ne pourriez pas vérifier la longueur car cela échouerait.


2
@ m.edmondson: Je ne suis pas vraiment convaincu. Un tableau pour les instances a LongLengthaussi un et un flux utilise longcomme longueur. Bien que ce soit une réponse valide, c'est une bonne façon de mesurer cela.
Willem Van Onsem

1
Mais les deux premiers bits sont utilisés pour l'indication ASCII / non ASCII comme le dit cet article , il devrait donc être 2 ^ 30 = 1 073 741 824
Saito

28

Pour tous ceux qui viennent sur ce sujet en retard, je pouvais voir que hitscan «vous ne devriez probablement pas faire ça» pourrait amener quelqu'un à demander ce qu'il doit faire…

La classe StringBuilder est souvent un remplacement facile. Considérez en particulier l'une des classes basées sur les flux , si vos données proviennent d'un fichier.

Le problème s += "stuff"est qu'il doit allouer une zone complètement nouvelle pour contenir les données, puis y copier toutes les anciennes données ainsi que les nouveaux éléments - CHAQUE ET CHAQUE ITERATION DE BOUCLE. Ainsi, ajouter cinq octets à 1 000 000 avec s += "stuff"est extrêmement coûteux. Si vous voulez simplement écrire cinq octets à la fin et poursuivre votre programme, vous devez choisir une classe qui laisse une certaine marge de croissance:

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

StringBuilderaugmentera automatiquement en doublant lorsque sa limite sera atteinte. Ainsi, vous verrez la douleur de croissance une fois au début, une fois à 5 000 octets, à nouveau à 10 000, à nouveau à 20 000. L'ajout de cordes entraînera la douleur à chaque itération de la boucle.


4
Il convient également de noter que StringBuilder vous permet de définir la taille initiale. Utile si vous savez que vous allez utiliser 10 000 000 d'entrées à l'avance, vous permettant d'ignorer une partie du resserrement.
Kyle Baran

3
+1 Pour voir à travers la question et répondre à un bon design. Comparativement, "c'est la taille de votre chaîne avant qu'elle ne souffle", par opposition à "si vous avez VRAIMENT besoin de stocker beaucoup de texte, utilisez ceci ..."
StevoInco

8

La longueur maximale d'une chaîne sur ma machine est de 1 073 741 791 .

Vous voyez, les chaînes ne sont pas limitées par un entier, comme on le croit généralement.

Mis à part les restrictions de mémoire, les chaînes ne peuvent pas avoir plus de 2 30 (1 073 741 824 ) caractères, car une limite de 2 Go est imposée par le Microsoft CLR (Common Language Runtime). 33 de plus que mon ordinateur ne le permettait.

Maintenant, voici quelque chose que vous pouvez essayer vous-même.

Créez une nouvelle application console C # dans Visual Studio, puis copiez / collez la méthode principale ici:

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

}

Mes résultats étaient les suivants:

Test de cordes, par Nicholas John Joseph Taylor

Théoriquement, C # devrait prendre en charge une chaîne de int.MaxValue, mais nous manquons de mémoire avant cela.

Il s'agit d'un test rapide pour affiner les résultats afin de trouver la longueur maximale prise en charge d'une chaîne.

Le test commence ... maintenant:

Longueur = 1000000000 au 08/05/2019 12:06

Une exception de type «System.OutOfMemoryException» a été levée. au 08/05/2019 12:06. Après décimation, la valeur de Increment est 100000000.

Une exception de type «System.OutOfMemoryException» a été levée. au 08/05/2019 12:06. Après décimation, la valeur de Increment est 10000000. Longueur s = 1010000000 au 08/05/2019 12:06 Longueur s = 1020000000 au 08/05/2019 12:06 Longueur s = 1030000000 au 08/05/2019 12 : 06 s.Longueur = 1040000000 au 08/05/2019 12:06 s.Longueur = 1050000000 au 08/05/2019 12:06 s.Longueur = 1060000000 au 08/05/2019 12:06 s.Longueur = 1070000000 à 08/05/2019 12:06

Une exception de type «System.OutOfMemoryException» a été levée. au 08/05/2019 12:06. Après décimation, la valeur de Increment est 1000000. Longueur s = 1071000000 au 08/05/2019 12:06 Longueur s = 1072000000 au 08/05/2019 12:06 Longueur s = 1073000000 au 08/05/2019 12 : 06

Une exception de type «System.OutOfMemoryException» a été levée. au 08/05/2019 12:06. Après décimation, la valeur de Increment est de 100000. Longueur s = 1073100000 au 08/05/2019 12:06 Longueur s = 1073200000 au 08/05/2019 12:06 Longueur s = 1073300000 au 08/05/2019 12 : 06 s. Longueur = 1073400000 au 08/05/2019 12:06 s. Longueur = 1073500000 au 08/05/2019 12:06 s. Longueur = 1073600000 au 08/05/2019 12:06 s. Longueur = 1073700000 à 08/05/2019 12:06

Une exception de type «System.OutOfMemoryException» a été levée. au 08/05/2019 12:06. Après décimation, la valeur de Increment est de 10000. Longueur s = 1073710000 au 08/05/2019 12:06 Longueur s = 1073720000 au 08/05/2019 12:06 Longueur s = 1073730000 au 08/05/2019 12 : 06 s. Longueur = 1073740000 au 08/05/2019 12:06

Une exception de type «System.OutOfMemoryException» a été levée. au 08/05/2019 12:06. Après décimation, la valeur de Increment est de 1000. s.Length = 1073741000 au 08/05/2019 12:06

Une exception de type «System.OutOfMemoryException» a été levée. au 08/05/2019 12:06. Après décimation, la valeur de Increment est de 100. Longueur s = 1073741100 au 08/05/2019 12:06 Longueur s = 1073741200 au 08/05/2019 12:06 Longueur s = 1073741300 au 08/05/2019 12 : 07 s. Longueur = 1073741400 au 08/05/2019 12 h 07 s. Longueur = 1073741500 au 08/05/2019 12 h 07 s. Longueur = 1073741600 au 08/05/2019 12 h 07 s. Longueur = 1073741700 à 08/05/2019 12:07

Une exception de type «System.OutOfMemoryException» a été levée. au 08/05/2019 12:07. Après décimation, la valeur de Increment est de 10. s.Length = 1073741710 au 08/05/2019 12:07 s.Length = 1073741720 au 08/05/2019 12:07 s.Length = 1073741730 au 08/05/2019 12 : 07 s. Longueur = 1073741740 au 08/05/2019 12:07 s. Longueur = 1073741750 au 08/05/2019 12:07 s. Longueur = 1073741760 au 08/05/2019 12:07 s. Longueur = 1073741770 à 08/05/2019 12:07 s.Longueur = 1073741780 à 08/05/2019 12:07 s.Longueur = 1073741790 à 08/05/2019 12:07

Une exception de type «System.OutOfMemoryException» a été levée. au 08/05/2019 12:07. Après décimation, la valeur de Increment est de 1. s.Length = 1073741791 au 08/05/2019 12:07

Une exception de type «System.OutOfMemoryException» a été levée. au 08/05/2019 12:07. Après décimation, la valeur de Increment est 0. Test terminé.

La longueur maximale d'une chaîne est 1073741791.

Appuyez sur n'importe quelle touche pour continuer.

La longueur maximale d'une chaîne sur ma machine est 1073741791.

J'apprécierais beaucoup que les gens puissent poster leurs résultats sous forme de commentaire ci-dessous.

Il sera intéressant de savoir si les gens obtiennent des résultats identiques ou différents.


"Vous voyez, les chaînes ne sont pas limitées par des nombres entiers comme on le croit généralement." -> un entier en c # peut aller jusqu'à 2147483647 et votre résultat est très proche (32 octets de moins) de cette valeur divisée par deux, ce qui est logique car chaque caractère d'une chaîne est stocké en Unicode sur deux octets. Donc, même si la limite n'est pas imposée par la taille de l'entier, elle est remarquablement proche de lui.
Ben

2

200 mégaoctets ... à ce moment-là, votre application s'arrête virtuellement, a environ une mémoire de jeu de travail et les o / s commencent à agir comme si vous deviez redémarrer.

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
Je ne suis pas sûr que le comportement que vous obtiendriez en créant une seule chaîne vraiment grosse soit le même que ce que vous voyez en allouant un tas d'entre eux et en concaténant.
Casey

2

Étant donné qu'il String.Lengths'agit d'un entier (c'est-à-dire d'un alias pour Int32), sa taille est limitée aux Int32.MaxValuecaractères unicode. ;-)

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.