7
class foo { }

writeln(foo.classinfo.init.length); // = 8 bytes

class foo { char d; }

writeln(foo.classinfo.init.length); // = 9 bytes

d は実際にこれらの 8 バイトに何かを格納していますか? もしそうなら、何を格納していますか? それは大きな無駄のように思えます。いくつかの値の型をラップするだけだと、特にそれらをたくさん使用している場合、クラスはプログラムを大幅に肥大化させます。char は 8 倍、int は 3 倍になります。

構造体の最小サイズは 1 バイトです。

4

4 に答える 4

9

D では、オブジェクトには 2 つのポインターを含むヘッダーがあります (したがって、アーキテクチャによっては 8 バイトまたは 16 バイトになる場合があります)。

最初のポインタは仮想メソッド テーブルです。これは関数ポインタで満たされたコンパイラによって生成される配列であるため、仮想ディスパッチが可能です。同じクラスのすべてのインスタンスは、同じ仮想メソッド テーブルを共有します。

2 番目のポインターはモニターです。同期に使用されます。D はローカル ストレージと不変性を強調しているため、多くのオブジェクトの同期が役に立たなくなるため、このフィールドが永遠にここに留まるとは限りません。このフィールドはこれらの機能よりも古いため、まだここにあり、使用できます。ただし、将来的には消滅する可能性があります。

オブジェクトのこのようなヘッダーは非常に一般的です。たとえば、Java や C# でも同じことがわかります。詳細については、こちらを参照してください: http://dlang.org/abi.html

于 2012-12-05T20:19:50.187 に答える
9

D は、各クラス インスタンスで 2 つの機械語を使用して、次のことを行います。

  1. 仮想関数テーブルへのポインター。これには、仮想メソッドのアドレスが含まれます。最初のエントリは、動的キャストでも使用されるクラスのclassinfoを指します。

  2. synchronized(obj)構文を許可するモニターは、ここに記載されています。

これらのフィールドについては、ここ (「クラス プロパティ」までスクロールダウン) およびここ (「クラス」までスクロールダウン) の D ドキュメントで説明されます

于 2012-12-05T20:19:54.387 に答える
0

Dの詳細はわかりませんが、Javaと.netの両方で、すべてのクラスオブジェクトにはそのタイプに関する情報が含まれており、モニターロックのターゲットであるかどうか、ファイナライズクリーンアップの対象であるかどうかなどの情報も保持されています。他のもの。すべてのオブジェクトがそのような情報を格納する標準的な手段を持つことで、言語やフレームワークのユーザーと実装者の両方にとって多くのことがより便利になります。ちなみに、.netの32ビットバージョンでは、オブジェクトの最小サイズが12バイトであることを除いて、各オブジェクトのオーバーヘッドは8バイトです。この最小値は、ガベージコレクターがオブジェクトを移動するときに、

編集 データ項目への参照を永続化できる必要があるためにクラスを使用する場合、スペースは貴重であり、データ項目がいつまだ有用でいつ廃止されるかがわかるような使用パターンです。構造体の配列を定義してから、インデックスを配列要素に渡すことができる場合があります。プログラムの構造により、割り当てられるすべてのアイテムが1回だけリリースされ、リリースされると使用されないようにすることができれば、これを非常に効率的に処理するコードを記述できます。

オブジェクトへの最後の参照がいつスコープ外になるかを簡単に判断できない場合は、8バイトが非常に妥当なレベルのオーバーヘッドになります。ほとんどのフレームワークでは、オブジェクトが32ビット境界に整列されると予想されます(したがって、バイトを追加すると、サイズが12ではなく9にプッシュされることに驚いています)。システムにコモドール64(*)よりも優れたガベージコレクターが搭載される場合、使用されているものと使用されていないものを示すために、オブジェクトごとに最小限のオーバーヘッドが必要になります。さらに、補足情報を含めることができるオブジェクトと含めることができないオブジェクトに別々のヒープを持たせたい場合を除いて、すべてのオブジェクトに補足情報ポインター用のスペースを含めるか、すべての補足情報用のスペースを含めます(ロック、放棄通知要求など)。2つのカテゴリのオブジェクトに別々のヒープを設定することが有益な場合もありますが、その利点が複雑さの追加を正当化することはほとんどありません。

(*)コモドール64ガベージコレクターは、メモリの先頭から下に向かって文字列を割り当てることで機能し、変数(GCされていない)はボトムアップで割り当てられました。メモリがいっぱいになると、システムはすべての変数をスキャンして、最上位のアドレスに格納されている文字列への参照を見つけます。次に、その文字列はメモリの最上部に移動され、その文字列へのすべての参照が更新されます。次に、システムはすべての変数をスキャンして、移動したばかりのアドレスの下の最も高いアドレスにある文字列への参照を見つけ、それに対するすべての参照を更新します。移動する文字列が見つからなくなるまで、このプロセスが繰り返されます。このアルゴリズムでは、文字列とともにメモリに追加のデータを保存する必要はありませんでしたが、もちろん非常に低速でした。コモドール128ガベージコレクターは、GCスペースの各文字列とともに、参照を保持する変数へのポインターと、GCスペースで次に低い文字列を見つけるために使用できる長さバイトを格納します。したがって、各文字列をチェックして、それがまだ使用されているかどうかを確認し、使用されている場合はメモリの先頭に再配置できます。はるかに高速ですが、文字列ごとに3バイトのオーバーヘッドが発生します。

于 2012-12-05T19:50:46.887 に答える
-2

さまざまなタイプのストレージ要件を調べる必要があります。すべての命令、ストレージ割り当て(つまり、変数/オブジェクトなど)は、特定のスペースを消費します。C#では、Int32タイプの整数オブジェクトは、4バイト(32ビット)の整数情報を格納する必要があります。オブジェクトであるため、他の情報も含まれている可能性がありますが、文字データ型にはおそらく1バイトの情報しか必要ありません。クラスのforまたはwhileのような構成要素がある場合、それらのそれぞれがクラスに何かをするように指示しているため、それらのこともスペースを占有します。クラス自体は、メモリ内に作成されるいくつかの命令を必要とします。これは、最初の8バイトを占めます。

アセンブラ言語コースを受講してください。これまでに知りたかったことをすべて学び、次に、プログラムがコンパイル時にメモリを大量に使用したり、ストレージを大量に消費したりする理由について学びます。

于 2012-12-05T19:50:57.523 に答える