6

多数の大きな文字列の連結を行ういくつかの操作があり、最近メモリ不足の例外が発生しました。残念ながら、これはお客様のサイトで発生しているため、コードのデバッグはオプションではありません。

コードのオーバーホールを検討する前に、大きな文字列に対する StringBuilder の RAM 消費特性はどのようなものでしょうか?

特に、標準の文字列型と比較すると。文字列のサイズは 10 MB をはるかに超えており、20 MB 前後で問題が発生するようです。

: これは速度ではなく、RAM に関するものです。

4

5 に答える 5

10

StringBuilder がスペースを使い果たすたびに、元のバッファーの 2 倍のサイズの新しいバッファーを再割り当てし、古い​​文字をコピーして、古いバッファーを GC します。2x が割り当て可能なメモリよりも大きくなるように、十分な量 (x と呼びます) を使用している可能性があります。文字列の最大長を決定し、それを StringBuilder のコンストラクターに渡して、事前に割り当て、2 倍の再割り当てに翻弄されないようにしたい場合があります。

于 2008-09-29T16:47:17.257 に答える
6

これは、文字列の連結とメモリの割り当てに関する優れた研究です。

連結を回避できる場合は、それを実行してください。

これは簡単です。連結する必要はないが、ソースコードの見栄えを良くしたい場合は、最初の方法を使用してください。単一の文字列であるかのように最適化されます。

+=連結は使用しないでください。あまりにも多くの変更が舞台裏で行われていますが、そもそも私のコードからは明らかではありません。String.Concat()をオーバーロード(2文字列、3文字列、文字列配列)で明示的に使用することをお勧めします。これにより、効率をチェックしながら、コードが何の驚きもなく何をするかが明確に示されます。

StringBuilderのターゲットサイズを見積もってみてください。

必要なサイズをより正確に見積もることができるほど、StringBuilderが内部バッファーを増やすために作成する必要のある一時的な文字列が少なくなります。

パフォーマンスが問題になる場合は、Format()メソッドを使用しないでください。

{x}の置換だけを使用しているときに、断片から配列を作成できる場合は、フォーマットの解析にオーバーヘッドがかかりすぎます。Format()は読みやすさには優れていますが、アプリケーションから可能なすべてのパフォーマンスを引き出す場合に行うべきことの1つです。

于 2008-09-29T17:54:34.380 に答える
3

ロープのデータ構造に興味があるかもしれません。この記事:ロープ: 理論と実践では、ロープの利点について説明しています。.NET の実装があるかもしれません。

[更新、コメントに答える] メモリ使用量は少ないですか? 記事でメモリを検索すると、いくつかのヒントが見つかります。
基本的に、必要なときにメモリを追加するだけなので、構造のオーバーヘッドにもかかわらず、はい。StringBuilder は、古いバッファを使い果たすと、はるかに大きなバッファを割り当て (すでに空のメモリを浪費する可能性があります)、古いバッファを削除する必要があります (ガベージ コレクションされますが、その間に多くのメモリを使用する可能性があります)。

.NET の実装は見つかりませんでしたが、少なくとも C++ の実装があります (SGI の STL: http://www.sgi.com/tech/stl/Rope.html )。おそらく、この実装を活用できます。私が参照するページには、メモリパフォーマンスに関する作業があることに注意してください。

ロープはすべての問題を解決できるわけではないことに注意してください。ロープの有用性は、大きな文字列の作成方法と使用方法に大きく依存します。記事では、長所と短所を指摘しています。

于 2008-09-29T19:28:38.007 に答える
1

Strigbuilderは、文字列の連結によって引き起こされるメモリの問題に対する完全に優れたソリューションです。

特定の質問に答えるために、Stringbuilderには、文字列の長さが現在割り当てられているStringbuilderバッファーの長さに等しい通常の文字列と比較して、一定のサイズのオーバーヘッドがあります。バッファは、結果として生じる文字列の2倍のサイズになる可能性がありますが、バッファがいっぱいになるまでStringbuilderに連結するときにメモリ割り当てが行われないため、これは本当に優れたソリューションです。

文字列と比較して、これは傑出しています。

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

このコードには、コードにリテラルとして格納された4つの文字列があります。2つはメソッドで作成され、1つは変数から作成されますが、6つの別々の中間文字列を使用します。このパターンを継続すると、GCが起動してクリーンアップするまで、指数関数的にメモリ使用量が増加します。

于 2008-09-29T17:20:42.713 に答える
-2

文字列ビルダーの正確なメモリパターンについてはわかりませんが、共通文字列はオプションではありません。

共通の文字列を使用すると、連結ごとに別の文字列オブジェクトが作成され、メモリ消費量が急増し、ガベージ コレクターが頻繁に呼び出されます。

string a = "a";

//creates object with a

a += "b"

/creates object with b, creates object with ab, assings object with ab to "a" pointer
于 2008-09-29T16:48:14.930 に答える