.NET Frameworkでブール値が4バイト、文字が2バイトを消費するのはなぜですか?ブール値は1ビットを占めるか、少なくとも文字よりも小さい必要があります。
9 に答える
これはメモリアライメントの問題です。4バイトの変数は2バイトの変数よりも高速に動作します。これが、カウンターなどにバイトやショートの代わりに整数を使用する必要がある理由です。
2バイトの変数は、メモリが速度よりも重要な場合にのみ使用する必要があります。これが、char(.NETではUnicode)が4バイトではなく2バイトを使用する理由です。
約boolean
他のほとんどの答えは間違っています-アライメントと速度は、コンパイラがバイトを4バイト幅にする理由ではなく、プログラマーがループカウンターの int に固執する必要がある理由です。実際、すべての推論は、ブール値だけでなく、バイトとショートにも当てはまります。
少なくともC#では、bool(またはSystem.Boolean)は1バイト幅の組み込み構造であり、自動的にボックス化できるため、オブジェクトがあります(少なくとも2つのメモリワードを表す必要があります。つまり、8 / 32/64 ビット環境でそれぞれ 16 バイト)、フィールド (少なくとも 1 バイト) とそれを指す 1 つのメモリ ワード、つまり合計で少なくとも 13/25 バイト。
これは実際、「C# プリミティブ型」に関する最初の Google エントリです。 http://msdn.microsoft.com/en-us/library/ms228360(VS.80).aspx
また、引用されたリンク ( http://geekswithblogs.net/cwilliams/archive/2005/09/18/54271.aspx ) にも、CLI 標準によるブール値は 1 バイトかかると記載されています。
ただし、実際には、これが見える唯一の場所はブール値の配列です。n 個のブール値は n バイトかかります。それ以外の場合は、1 つのブール値が 4 バイトかかる場合があります。
- 構造内では、ほとんどのランタイム (Java でも) は、パフォーマンスのためにすべてのフィールドを 4 バイト境界に揃えます。組み込みデバイス用の Monty JVM はより賢明です。フィールドを最適に並べ替えると思います。
- インタープリターのローカル フレーム/オペランド スタックでは、ほとんどの実装で、パフォーマンスのために、1 つのスタック エントリは 1 メモリ ワード幅です (おそらく .NET では double と long をサポートするために 64 ビット幅でなければなりません。 Java では 2 つではなく、1 つのスタック エントリのみを使用します)。追加のオーバーヘッドに見合うだけの価値がある場合、JIT コンパイラは代わりに、パフォーマンスに影響を与えずにフィールドを並べ替えることで他の var を整列させながら、boolean ローカルに 1 バイトを使用できます。
約char
char
国際化のサポートが必要な場合、内部で 2 バイト文字を使用するのが最も安全な方法であるためです。これは、Unicode をサポートすることを選択したこととは直接関係ありませんが、UTF-16 と Basic Multilingual Plane に固執することを選択したこととは関係ありません。Java と C# では、常に 1 つの論理 char が char 型の変数に収まると想定できます。
これは、32ビット環境では、CPUが8ビットまたは16ビット値よりも高速に32ビット値を処理できるため、これは速度とサイズのトレードオフです。メモリを節約する必要があり、ブール値が大量にある場合は、uintを使用して、ブール値を4バイトのuintのビットとして保存します。文字は16ビットのUnicode文字を格納するため、2バイト幅です。
メモリ ストレージのわずかな違いに関係なく、true/false の yes/no 値にブール値を使用することは、開発者 (1 年後にコードを再確認する必要がある場合に自分自身を含む) にとって重要です。これは、意図をより正確に反映するためです。コードをより理解しやすくすることは、2 バイトを節約することよりもはるかに重要です。
コードが意図をより正確に反映するようにすると、一部のコンパイラの最適化が悪影響を与える可能性も低くなります。このアドバイスは、プラットフォームやコンパイラを超えています。
また、boolean を使用して保守可能なコードを作成する必要があります。何かがブール値であることを確認するコードをちらっと見ている場合は、char をブール値として使用していることを理解するためにメモリを節約する価値があります。
「実際、ブール値は2ではなく4バイトです。理由は、CLRがブール値をサポートしているためです。32ビット値の方が操作がはるかに効率的であるため、時間と空間がはるかに効率的であるため、これが機能すると思います。トレードオフは、一般的に、それだけの価値があります。大量のビットをまとめる必要がある場合は、ビットベクトルクラスを使用する必要があります(現在の場所は忘れてください)...」
それはhttp://geekswithblogs.net/cwilliams/archive/2005/09/18/54271.aspxでポールウィックによって書かれました
メモリが問題になるのは、ビットの配列が大きい場合のみです。この場合、System.Collections.BitArray クラスを使用できます。
まず、プロファイラーを使用して、どこにメモリの問題があるかを判断する必要があります。
これは、Windows と .Net が当初から内部文字セットとして Unicode (UTF 16)を使用してきたためです。UTF 16は、1 文字あたり 2 バイト、または 1 文字あたり 2 バイトの単語のペアを使用しますが、これは可変幅エンコーディングであるため、必要な場合に限ります。
「Basic Multilingual Plane (BMP) の文字の場合、結果のエンコーディングは単一の 16 ビット ワードになります。他のプレーンの文字の場合、エンコーディングは 16 ビット ワードのペアになります」
ブール値に関する私の推測では、デフォルトのレジスタは 32 ビットであるため、4 バイトであり、これが最小サイズになります。ビット単位の演算を使用しない限り、Net は論理演算を効率的に実行できます。