StringBuilder.ToString() throws exception OutOfMemoryException
J'ai créé une StringBuilder
de longueur "132370292", quand j'essaie d'obtenir de l'aide de la chaîne de la ToString()
méthode il jette OutOfMemoryException
.
StringBuilder SB = new StringBuilder();
for(int i =0; i<=5000; i++)
{
SB.Append("Some Junk Data for testing. My Actual Data is created from different sources by Appending to the String Builder.");
}
try
{
string str = SB.ToString(); //Throws OOM mostly
Console.WriteLine("String Created Successfully");
}
catch(OutOfMemoryException ex)
{
StreamWriter sw = new StreamWriter(@"c:\memo.txt", true);
sw.Write(SB.ToString()); //Always writes to the file without any error
Console.WriteLine("Written to File Successfully");
}
Quelle est la raison de l'OOM lors de la création d'une nouvelle chaîne et pourquoi il ne jette pas OOM lors de l'écriture dans un fichier?
Détails d'une Machine 64 bits, Windows 7, 2 go de RAM, .NET version 2.0
Quel est le contenu de
Pourquoi cette longueur exagérée? Vous venez réservés 126 MO de mémoire.
Pouvez-vous poster le code de votre programme?
Mon code est très différente, je suis de la création de la StringBuilder à partir de différentes sources en Ajoutant les valeurs, et la Longueur finale de la SB est "132370282". SB.ToString() fonctionne très bien, à certains moments, et ne parvient pas, à certains moments.
C'est 252MB; pourquoi voulez-vous une 252MB chaîne? Cela semble un incroyablement mauvaise idée - vous devrait vraiment être écrit à l'auteur (
mytext
? Et pourquoi écrivez-vous à un StringBuilder
si et puis à un flux? Pourquoi pas le flux directement en utilisant un StringWriter
?Pourquoi cette longueur exagérée? Vous venez réservés 126 MO de mémoire.
Pouvez-vous poster le code de votre programme?
Mon code est très différente, je suis de la création de la StringBuilder à partir de différentes sources en Ajoutant les valeurs, et la Longueur finale de la SB est "132370282". SB.ToString() fonctionne très bien, à certains moments, et ne parvient pas, à certains moments.
C'est 252MB; pourquoi voulez-vous une 252MB chaîne? Cela semble un incroyablement mauvaise idée - vous devrait vraiment être écrit à l'auteur (
sw
), cumulativement, - et non de la construction de la chose entière dans la mémoire. (/cc @DebugErr juste à noter que c'est 252MB, pas 126MB)OriginalL'auteur Thiru | 2014-07-29
Vous devez vous connecter pour publier un commentaire.
Parce que vous êtes à court de mémoire - ou au moins, le CLR ne peut pas allouer un objet avec la taille que vous avez demandé. C'est vraiment aussi simple que cela. Si vous voulez éviter les erreurs, ne pas essayer de créer des chaînes qui ne rentrent pas dans la mémoire. Notez que même si vous avez beaucoup de mémoire, et même si vous exécutez une version 64 bits du CLR, il y a des limites à la taille des objets qui peuvent être créés.
Parce que vous avez plus d'espace disque que la mémoire.
Je suis sûr que le code n'est pas exactement comme vous le décrivez. Cette ligne ne parviennent pas à compiler:
... parce que la méthode est
Write
plutôt quewrite
. Et si vous êtes fait appelSB.ToString()
, alors que c'est tout autant de chances d'échouer questr = SB.ToString()
.Il semble plus probable que vous êtes fait l'écriture du fichier dans un flux de mode, par exemple,
De cette façon, vous n'aurez jamais à avoir de grandes quantités de texte dans la mémoire - il est juste écrit sur le disque comme il va, peut-être avec certains de mise en mémoire tampon, mais pas assez pour causer des problèmes de mémoire.
ToString
dans les deux cas, ne serait pas le fait qu'il est écrit sur le disque être un détail sans importance ici?Les deux probablement hors - 64bit processus permettrait d'avoir beaucoup de mémoire, mais probablement s'exécute qu'en 32bit et frappe l'adresse de la fragmentation de l'espace; il est probable réussit à écrire sur le disque, car il est déjà converti résultat à la chaîne une fois et appel précédent n'a pas manqué (basés sur un échantillon de code)
Voir ma mise à jour - ce n'est pas le code réel.
L'exemple de code n'est pas le code réel de toute façon, mais même dans une version 64 bits du CLR, la taille de l'objet est limité. Aussi, si vous appelez
ToString()
sur unStringBuilder
deux fois, il crée tout de même deux chaînes - au moins dans les essais que je viens de lancer... (compte tenu de l'utilisation de .NET 2.0, qui n'aurait pas été le cas à l'époque...)Convenu, n'est-ce pas repérer les minuscules w, et puisque cela signifie qu'il n'est évidemment pas le bon code, tous les paris sont éteints.
OriginalL'auteur Jon Skeet
Solution de contournement: Supposons que vous voulez écrire une chaîne de caractères stockée dans StringBuilder pour un StreamWriter, je voudrais faire une écriture de cette façon pour éviter de SB.ToString de l'OOM exception. Mais si votre OOM exception est due à StringBuilder du contenu d'ajouter lui-même, vous devez travailler sur.
Vous avez probablement penser à la façon dont il est codé, plutôt que la façon dont vous voulez que le code de l'être. Je crois que mon code ci-dessus fonctionne bien et vous encourager à vous de débogage et de le vérifier.
Oui, vous avez raison, c'est correct. Et il semble préférable de le faire à votre façon. Je suis désolé d'avoir douté de vous :). Bien que je voudrais nommer les variables de mieux (stringBuilder, faire un "tampon" de la variable pour la ToString).
OriginalL'auteur Titus
Vous devez vous rappeler que les chaînes de caractères .NET sont stockées dans la mémoire 16 bits unicode. Cela signifie chaîne de caractères de longueur 132370292 sera reqire de 260 mo de RAM.
En outre, lors de l'exécution de
vous créez une COPIE de votre chaîne de caractères (un autre de 260 mo).
Gardez à l'esprit que chaque processus a sa propre limite de RAM donc OutOfMemoryException peut être levée même si vous avez certains de RAM libre à gauche.
char
est de 2 octets, de sorte que vous devez doubler tous ces chiffresVrai, mise à jour de la réponse. Merci pour l'erreur.
OriginalL'auteur semao