Unity 文字列のパフォーマンスの問題

序文

本やインターネットで学んだ知識を共有します。
文字列を動的に作成するたびに、C# は文字列を割り当てるためにヒープ メモリにメモリを割り当てます。C# には文字列のキャッシュ メカニズムがないため、すべての接続が切断されます。 , とその組み合わせ。毎回新しいメモリが適用され、元のメモリは破棄されて GC を待ち、GC は大量の CPU スペースを消費します。たとえば、a = "ax"; c = "b" の場合+ a + "c" の場合、ある程度のパフォーマンスの無駄が発生します。ここでの + 演算子はコンパイル時ではなく実行時に実行されるためです。したがって、+ 操作ごとに、元のオブジェクトを変更するのではなく、新しい文字列オブジェクトが作成されます。これにより、メモリ領域を占有する 2 つの無駄な中間オブジェクト "bax" と "baxc" が生成されます。注意しないと、プログラムの遅延が徐々に増加し、操作効率が低下します。文字列の効率を向上させる方法はいくつかあります。お支払いください。注意: StringFormat、+ スプライシングおよび $ 構文シュガーを使用すると、効率上の問題が発生します。効率を向上させるには、StringBuilder を使用してください。ただし、読みやすさを考慮して、文字列が短く、頻度が低い場合は、構文シュガーで十分です。

id - 文字列辞書プール


Key-string キャッシュ プールを自分で構築し、戦闘中にプールからDict<int,string>を探してGC を減らします。

Dictionary<int,string> strCache;
string strName = null;
if(!strCache.TryGetValue(id, out strName))
{
ResData resData = GetDataById(ID);
string strName = "This is " + resData,Name;
strCache.Add(id,strName);
}
return strName;

固定長の文字列プールを作成し、ポインタを使用して文字列を結合します

ポインタをターゲット文字列にポイントし、strA と strB をそれぞれ前と後ろの位置に配置して、メモリの割り当てと解放の数を減らします。

public unsafe string Concat(string strA, string strB)  
{  
    int a_length = strA.Length;  
    int b_length = strB.Length;  
    int sum_length = a_length + b_length;  
    string strResult = null;  
    if (!cacheStr.TryGetValue(sum_length, out strResult))  
    // 如果不存在 sum_length 长度的缓存字符串,那么直接连接后存入缓存  
    {  
        strResult = strA + strB;        cacheStr.Add(sum_length, strResult);  
        return strResult;  
    }    //字符串再利用  
    fixed (char* strA_ptr = strA)  
    {        fixed (char* strB_ptr = strB)  
        {            fixed (char* strResult_ptr = strResult)  
            {                memcopy((byte*)strResult_ptr, (byte*)strA_ptr, a_length * sizeof(char));  
                memcopy((byte*)strResult_ptr+a_length,(byte*)strB_ptr,b_length * sizeof(char));  
            }        }    }    return strResult;  
}

メモリコピー関数

public unsafe void memcopy(byte* dest, byte* src, int len)  
{  
    while((--len)>=0)  
    {dest[len] = src[len];}}

文字列ビルダー

また、文字列を複数回作成して繰り返し結合する場合の GC 問題も解決できます。StringBuilder は変数であるため、新しい文字列オブジェクトを作成せずに元の文字列を変更できるため、メモリ領域を節約でき、効率が向上します。StringBuilder は、builder.Append("a").Append("b").Append("c") などの複数の文字列操作を簡単に実行できるチェーン呼び出しをサポートしています。StringBuilder は容量を動的に調整でき、文字列の長さが現在の容量を超えた場合、例外をスローせずに自動的に容量を拡張します。
欠点は、stringBuilder がスレッドセーフでないことです。つまり、マルチスレッド環境では、複数のスレッドが同じ StringBuilder オブジェクトを同時に変更すると、データの不整合やエラーが発生する可能性があります。StringBuilder の ToString メソッドは、内部の文字配列を走査して新しい文字列オブジェクトに結合する必要があり、このプロセスにはある程度の時間とリソースが消費される場合があります。StringBuilder は、toString 中に文字列を 1 回だけ作成するため、以前に文字列を複数回作成する場合に比べて、CPU パフォーマンスへの負担が大幅に軽減されます。

おすすめ

転載: blog.csdn.net/TongOuO/article/details/132522681