Question

Nous avons quelques opérations où nous effectuons un grand nombre de concaténations de chaînes volumineuses et avons récemment rencontré une exception de mémoire insuffisante. Malheureusement, le débogage du code n'est pas une option, car cela se produit sur un site client.

Avant d’envisager une refonte de notre code, j'aimerais demander: quelles sont les caractéristiques de consommation de RAM de StringBuilder pour les grandes chaînes?

Surtout qu’ils se comparent au type de chaîne standard. La taille des chaînes de caractères dépasse largement les 10 Mo, et nous semblons nous heurter aux problèmes autour de 20 Mo.

REMARQUE : il ne s'agit pas de vitesse, mais de mémoire vive.

Était-ce utile?

La solution

Voici une belle étude sur la Concaténation de chaînes et allocation de mémoire .

  

Si vous pouvez éviter la concaténation, faites-le!

     

Ceci est une évidence, si vous ne le faites pas   doivent concaténer mais veulent votre   le code source pour bien paraître, utilisez le   première méthode. Il sera optimisé comme   s'il s'agissait d'une seule chaîne.

     

N'utilisez jamais le signe + = concaténant. Trop de changements se produisent.   dans les coulisses, ce qui n'est pas évident   de mon code en premier lieu. je   conseille d'utiliser plutôt String.Concat ()   explicitement avec une surcharge (2   chaînes, 3 chaînes, tableau de chaînes).   Cela montrera clairement ce que votre code   fait sans surprises, alors que   vous permettant de garder un œil sur   l'efficacité.

     

Essayez d'estimer la taille cible d'un constructeur de chaînes.

     

Plus vous pouvez estimer avec précision le   taille nécessaire, le moins temporaire   les chaînes que le StringBuilder devra   créer pour augmenter son interne   tampon.

     

N'utilisez aucune méthode Format () lorsque les performances sont problématiques.

     

Trop de frais généraux sont impliqués dans   analyser le format, quand vous pourriez   construire un tableau en morceaux lorsque   tout ce que vous utilisez sont {x} remplace.   Format () est bon pour la lisibilité, mais   une des choses à faire quand vous êtes   presser toutes les performances possibles   de votre application.

Autres conseils

À chaque fois que StringBuilder manque d'espace, il réaffecte un nouveau tampon deux fois plus grand que le tampon d'origine, copie les anciens caractères et laisse l'ancien tampon à la position GC. Il est possible que vous en utilisiez suffisamment (appelez-le x) pour que 2x soit plus grand que la mémoire que vous êtes autorisé à allouer. Vous souhaiterez peut-être déterminer une longueur maximale pour vos chaînes et la transmettre au constructeur de StringBuilder afin que vous effectuiez une préallocation et que vous ne soyez pas à la merci de la réallocation de doublage.

Vous pourriez être intéressé par la structure de données des cordes. Cet article: Cordes: Théorie et pratique expliquent leurs avantages. Peut-être qu’il existe une implémentation pour .NET.

[Mise à jour, pour répondre au commentaire] Est-ce qu'il utilise moins de mémoire? Dans mémoire , recherchez quelques astuces dans l'article.
Fondamentalement, oui, malgré la surcharge de la structure, car elle ajoute simplement de la mémoire en cas de besoin. StringBuilder, lorsqu’il utilise l’ancien tampon, doit en allouer un beaucoup plus grand (ce qui peut déjà gaspiller de la mémoire vide) et abandonner l’ancien (qui sera récupéré, mais pourra utiliser encore beaucoup de mémoire entre-temps).

Je n'ai pas trouvé d'implémentation pour .NET, mais il existe au moins une implémentation C ++ (dans le STL de SGI: http://www.sgi.com/tech/stl/Rope.html ). Peut-être que vous pouvez tirer parti de cette mise en œuvre. Notez que la page que je référence ont un travail sur les performances de la mémoire.

Notez que les cordes ne permettent pas de résoudre tous les problèmes: leur utilité dépend énormément de la manière dont vous construisez vos grandes chaînes et de la façon dont vous les utilisez. Les articles soulignent les avantages et les inconvénients.

Strigbuilder est une solution parfaite aux problèmes de mémoire causés par la concaténation de chaînes.

Pour répondre à votre question spécifique, Stringbuilder a un temps système de taille constante comparé à une chaîne normale dans laquelle la longueur de la chaîne est égale à la longueur de la mémoire tampon Stringbuilder actuellement allouée. Le tampon pourrait potentiellement avoir deux fois la taille de la chaîne résultante, mais aucune concordance supplémentaire ne sera faite lors de la concaténation avec le constructeur de chaînes jusqu'à ce que le tampon soit rempli. Il s'agit donc d'une excellente solution.

Par rapport à la chaîne, c'est exceptionnel.

string output = "Test";
output += ", printed on " + datePrinted.ToString();
output += ", verified by " + verificationName;
output += ", number lines: " + numberLines.ToString();

Ce code comporte quatre chaînes stockées sous forme de littéraux dans le code, deux créées dans les méthodes et une à partir d'une variable, mais utilisant six chaînes intermédiaires distinctes de plus en plus longues. Si ce modèle se poursuit, l'utilisation de la mémoire augmentera de façon exponentielle jusqu'à ce que le CPG entame le nettoyage.

Je ne connais pas exactement le modèle de mémoire du constructeur de chaînes, mais la chaîne commune n'est pas une option.

Lorsque vous utilisez la chaîne commune, chaque concaténation crée un autre couple d'objets chaîne et la consommation de mémoire monte en flèche, ce qui rend le garbage collector appelé trop souvent.

string a = "a";

//creates object with a

a += "b"

/creates object with b, creates object with ab, assings object with ab to "a" pointer
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top