66

クラスがあるとしましょう。

class Foo
{
    public static bar;
}

あなたが言う時:

new Foo();

メモリ内では、このオブジェクト用にスペースが予約されていると想像できます。

...そしてあなたがもう一度言うとき:

new Foo(); 

...これで、オブジェクトに使用できる別のスペースができました。

しかし、静的フィールドは正確にどこに存在しますか?

私が本当に学ぼうとしているのは:

オブジェクトへの参照は、それらが参照するオブジェクトの同じフィールドをどのように参照しますか?

4

11 に答える 11

118

型システムの正確な詳細は実装に依存しますが、それが依存しているので気にしないでくださいと述べるだけでなく、もう少し詳しく説明します。ジェフリー・リッチターによる「 C#経由のCLR 」という本と、ハヌ・コンマラパティらによる「CLRがランタイムオブジェクトを作成する方法」の記事に従って、Microsoftの実装(.NET)でおおよそどのように機能するかを説明します。(元のMSDN 2005年5月号)。


クラスがあるとしましょう:

class Foo
{
    // Instance fields
    string myBar = "Foobar";
    int myNum;

    // Static fields
    static string bar = "Foobar";
    static int num;
}

Foo myFoo = new Foo();
Type typeOfFoo = typeof(Foo);

インスタンスフィールドはどこにありますか?

と言うとnew Foo()、オブジェクトインスタンスにスペースが割り当てられて初期化され、コンストラクターが呼び出されます。このインスタンスは、下の画像にFooのインスタンスとして示されています。たとえば、instanceには、クラスのインスタンスフィールド(この場合はmyBarand myNum)のみが含まれ、ヒープに割り当てられたオブジェクトの場合、ランタイム(Sync block indexおよびType handle)によって使用される2つの追加フィールドが含まれます。タイプハンドルは、インスタンスのタイプ(この場合はFooTypeのタイプ)を記述するオブジェクトへのポインターです。

もう一度言うnew Foo()と、新しいスペースが割り当てられ、そのタイプのインスタンスフィールド用のスペースが再び含まれます。ご覧のとおり、インスタンスフィールドはオブジェクトインスタンスに関連付けられています。

ランタイムは、各インスタンスフィールドを、オブジェクトのデータの先頭から固定されたオフセットに配置します。たとえば、myBarオフセット+4に住んでいる可能性があります。インスタンスフィールドのアドレスは、単にオブジェクトのアドレスにフィールドのオフセットを加えたものです。

静的フィールドはどこにありますか?

C#およびJavaの静的フィールドは、オブジェクトインスタンスではなく、型に関連付けられています。クラス、構造体、列挙型はタイプの例です。静的フィールドの値を保持するために割り当てられるスペースは、(タイプごとに)1回だけです。タイプごとにオブジェクトTypeが1つしかないため、タイプを説明する構造内の静的フィールドにスペースを割り当てることは理にかなっています。Typeこれは、C#とJavaで採用されているアプローチです。

Typeオブジェクト1は、タイプがランタイムによってロードされるときに作成されます。この構造には、ランタイムが新しいインスタンスを割り当てたり、メソッドを呼び出したり、キャストを実行したりするために必要なあらゆる種類の情報が含まれています。また、静的フィールド(この場合はbarと)用のスペースも含まれていますnum

ランタイムは、タイプのデータの先頭からオフセットして各静的フィールドを配置しました。これはタイプごとに異なります。たとえば、barオフセット+64で動作する可能性があります。静的フィールドのアドレスは、Typeオブジェクトのアドレスにフィールドのオフセットを加えたものです。タイプは静的に既知です。

いくつかのオブジェクト構造とそれらの関係を表示します。

1)Microsoft .NETでは、複数の異なる構造体が、MethodTableEEClass構​​造体などの型を記述します。

于 2013-03-02T18:10:11.380 に答える
16

これは、問題の実装に完全に依存します。C#およびJavaの場合、ランタイムは変数のメモリを格納する場所を決定できます。Cおよびほとんどのコンパイル言語の場合、コンパイラーがこの決定を行います。

そうは言っても、実際には、それは問題ではありません。仕様によって決定された使用法なので、動作が保証されることを知っている変数を自由に使用できます。

于 2013-02-08T22:02:57.793 に答える
6

Javaの場合、静的フィールドによって参照されるオブジェクトは、他のオブジェクトと同様にヒープ上に存在します。

ヒープは、すべてのクラスインスタンスと配列のメモリが割り当てられるランタイムデータ領域です。

クラスがロードされると、フィールドが初期化されます(宣言に初期化が含まれている場合)。これは、次のいずれかが最初に発生する直前に発生します。

  • クラスのインスタンスが作成されます。
  • クラスによって宣言された静的メソッドが呼び出されます。
  • クラスによって宣言された静的フィールドが割り当てられます。
  • クラスによって宣言された静的フィールドが使用され、フィールドは定数変数ではありません(§4.12.4)。

静的フィールドへのアクセスは、getstaticputstaticの2つの特別なJVM命令を介して行われます。ただし、その違いを除けば、静的フィールドは非静的フィールドに似ています。

于 2013-02-26T20:02:33.923 に答える
5

私はC#に精通しているだけで、これが私の理解です。

次に、プログラムが起動し、関連するすべてのアセンブリがAppDomainにロードされます。assamblyがロードされると、静的フィールドを含むすべての静的コンストラクターが呼び出されます。それらはそこに存在し、それらをアンロードする唯一の方法は、AppDomainをアンロードすることです。

于 2013-02-08T22:05:28.620 に答える
5

例外があるかもしれませんが、参照型の場合、 new-keywordは通常、「ヒープ」と呼ばれる内部データ構造でオブジェクトを作成します。ヒープはCLR(共通言語ランタイム)によって管理されます。静的メンバー、インスタンスメンバー、またはローカル変数のどちらを使用しても違いはありません。

静的メンバーとインスタンスメンバー(キーワードのないメンバー)の違いstaticは、静的メンバーはタイプ(class、struct)ごとに1回だけ存在し、インスタンスメンバーはインスタンスごと(オブジェクトごと)に1回存在することです。

静的であるかどうかは参照のみです。この区別は、参照されるオブジェクトには適用されません(オブジェクトが値型でない場合)。静的メンバー、インスタンスメンバー、およびローカル変数はすべて同じオブジェクトを参照できます。

于 2013-02-26T18:24:06.113 に答える
5

これは言語ごとに大きく異なり、プラットフォームごとに大きく異なる場合もあります...

たとえば、.NET側では、静的メンバーは管理EEClass定義に「関連付け」られます。これ、ヒープに割り当てられたメンバーでも、「どこでも」割り当てられたメンバーでもかまいません(C#仕様では、ヒープ/スタックの動作は指定されていません。これは実装です VMの詳細)

于 2013-02-08T22:03:01.463 に答える
3

静的メンバーと定数はヒープに格納されます。ガベージコレクションを取得できるヒープ上のオブジェクトとは異なり、静的メンバーと定数はAppdomainが破棄されるまで保持されるため、静的フィールドの処理には注意が必要です。

于 2013-04-04T14:33:11.387 に答える
2

静的変数はオブジェクトではなくクラスに属しているため、bar何千ものインスタントを初期化しても、メモリには1つしかありませんFoo

于 2013-02-08T22:02:50.080 に答える
1

これは、言語ごとに、または言語の設計者によって異なります。Javaについて言えば、静的メンバーはJVMのメソッド領域に格納され、すべてのオブジェクトがそれらにリンクされています。知っておくべきもう1つの重要なことは、クラスのオブジェクトを作成せずに静的データメンバーにアクセスできることです。つまり、静的データメンバーへのメモリの割り当ては、そのオブジェクトの作成に依存しません。クラス。

于 2013-02-27T02:34:47.353 に答える
1

仕様により、静的変数は定数プールに格納されます。JVMは、この情報を永続生成に格納します。

于 2013-03-03T10:01:52.590 に答える
0

通常、静的変数はプログラムメモリのデータセグメントに格納されます。したがって、実行中のプログラムで作成された/存在するすべてのクラスについて、データセグメントに静的変数が作成され、他のすべての変数はコードセグメントで初期化されます。

基本的には

+++++++++++++++++++++++++++++++++++++
+ DATA Segment
+   -static vars
+   
+----------------------------------
+  instances | instances | instances|
+            |           |          |

ここでは、単一の領域がインスタンス間で共有されます。

ウィキペディアから「データ領域には
、値で明示的に初期化 された、プログラムによって使用されるグローバル変数と静的変数が含まれています。」

于 2013-03-05T14:29:28.740 に答える