「en」などの言語コード文字列を保存する必要があります。これには常に2文字が含まれます。
タイプを「String」または「Char」として定義する方がよいでしょうか。
private string languageCode;
vs
private char[] languageCode;
または、別のより良いオプションはありますか?
これら2つはどのようにメモリに保存されますか?値が割り当てられたときに、それらに何バイトまたはビットが割り当てられますか?
「en」などの言語コード文字列を保存する必要があります。これには常に2文字が含まれます。
タイプを「String」または「Char」として定義する方がよいでしょうか。
private string languageCode;
vs
private char[] languageCode;
または、別のより良いオプションはありますか?
これら2つはどのようにメモリに保存されますか?値が割り当てられたときに、それらに何バイトまたはビットが割り当てられますか?
保管方法
string
と の両方がchar[]
ヒープに格納されるため、ストレージは同じです。内部的には、単に便利にするための余分なコードがたくさんstring
あるカバーだchar[]
と思います。
また、繰り返し文字列がたくさんある場合は、Interningを利用してそれらの文字列のメモリ フットプリントを減らすことができます。
より良い選択肢
私は文字列を好むでしょう - データ型が何であり、それをどのように使用するつもりであるかがすぐに明らかになります. また、人々は文字列の使用に慣れているため、保守性が損なわれることはありません。また、作成されたすべてのボイラープレート コードからも大きなメリットが得られます。string
Microsoft はまた、この型がパフォーマンスを浪費しないようにするために多大な努力を払ってきました。
割り当てサイズ
文字列は、Unicode 文字を格納するのに十分なだけ割り当てるという点で非常に効率的であると思います。文字列は不変であるため、これを行うのは安全です。配列は、新しい配列にスペースを割り当てずにサイズを変更することもできないため、必要なものだけを取得すると仮定します。
代替案
言語コードは 20 しかなく、パフォーマンスが重要であるという情報に基づいて、コードを表すために必要なサイズを削減するために、独自の列挙型を宣言できます。
enum LanguageCode : byte
{
en = 0,
}
char
これは、(配列内の) 2 つに対して 4+ とは対照的に、1 バイトしか必要としませんが、使用可能なLanguageCode
値の範囲をbyte
- の範囲に制限します。これは、20 項目に対して十分な大きさです。
sizeof()
演算子を使用して値型のサイズを確認できます: sizeof(LanguageCode)
。列挙型はフードの下の基になる型に過ぎず、デフォルトは ですint
が、私のコードサンプルでわかるように、新しい型を「継承」することでそれを変更できます。
簡単な答え: 文字列を使用
長い答え:
private string languageCode;
私の知る限り、文字列は長さのプレフィックス付きの文字配列として保存されます。String オブジェクトはヒープ上でインスタンス化され、この未加工の配列を維持します。しかし、String オブジェクトは単なる配列ではなく、比較、連結、部分文字列の抽出、検索などの基本的な文字列操作を可能にします。
その間
private char[] languageCode;
文字の配列として格納されます。つまり、配列オブジェクトがヒープ上に作成され、文字の管理に使用されます。ただし、内部に保存される長さ属性はまだあるため、文字列と比較した場合、メモリの明らかな節約はありません。おそらく配列は文字列よりも単純であり、内部変数が少ないため、メモリフットプリントが少なくなります(これは確認する必要があります)。
しかし、OTOH では、この char 配列に対して文字列操作を実行する機能が失われます。文字列比較のような操作でさえ、今や面倒になります。簡単に言えば、文字列を使用してください。
これら2つはどのようにメモリに保存されますか? 値が割り当てられたときにそれらに割り当てられるバイト数またはビット数は?
.NET のすべてのインスタンスIntPtr
は次のように格納されます。型識別子用の 1 つのサイズのフィールド。インスタンスをロックするためにもう 1 つ。残りは、 のサイズに切り上げられたインスタンス フィールド データIntPtr
です。したがって、32 ビット プラットフォームでは、すべてのインスタンスが8 バイト + フィールド データを占有します。
string
これは aと a の両方に当てはまりますchar[]
。これらはどちらも、データの長さを IntPtr サイズの整数として格納し、その後に実際のデータを格納します。したがって、2 文字string
と 2 文字char[]
の は、32 ビット プラットフォームでは 8+4+4 = 16 バイトを占有します。
正確に 2 文字を格納するときにこれを減らす唯一の方法は、実際の文字、または文字を含む構造体をフィールドまたは配列に格納することです。これらはすべて、文字に 4 バイトしか消費しません。
// Option 1
class MyClass
{
char Char1, Char2;
}
// Option 2
class MyClass
{
CharStruct chars;
}
...
struct CharStruct { public char Char1; public char Char2; }
MyClass
インスタンスごとに 8 バイト (32 ビット マシン上) と、文字用の 4 バイトを使用することになります。
// Option 3
class MyClass
{
CharStruct[] chars;
}
これは、MyClass オーバーヘッドに 8 バイト、chars
参照に 4 バイト、配列のオーバーヘッドに 12 バイト、配列ごとCharStruct
に 4 バイトを使用します。
正確に 2 文字を保存し、それを最も効率的に行いたい場合は、構造体を使用します。
struct Char2
{
public char C1, C2;
}
通常、この構造体を使用しても、新しいヒープ割り当ては発生しません。既存のオブジェクトを(可能な限り最小限に)拡大するか、非常に安価なスタックスペースを消費します。
実際、文字列には 1 ポインター長のサイズ オーバーヘッドがあります。つまり、32 ビット プロセスでは 4 バイト、64 ビット プロセスでは 8 バイトです。しかし、繰り返しますが、文字列は char 配列よりもはるかに多くの見返りを提供します。
アプリケーションが多くの短い文字列を使用し、それらの文字列プロパティとメソッドを頻繁に使用する必要がない場合は、おそらく数バイトのメモリを確保できます。ただし、それらのいずれかを文字列として使用する場合は、最初に新しい文字列インスタンスを作成する必要があります。これが、トラブルに見合うだけの十分なメモリを確保するのにどのように役立つかわかりません。