非標準の.Netアンケートを提供しています

私は、.Netプラットフォームに関する標準的ではない調査を提案します。 ネタバレは質問への回答を明らかにしましたが、それでも私はあなたに最初にアンケートに自分で答えてから、答えを見に行ってください:)



静的メソッドが呼び出されると、JIT ...
JITはプロキシメソッドへの呼び出しをコンパイルします。これにより、必要なコンパイラの無条件遷移が行われ、プロキシへの遷移のアドレスが新しいメソッド本体に置き換えられます。 これにはいくつかの理由があります。



最初に、メソッドがコンパイルされるとき、他のメソッドのすべての呼び出しポイントはコンパイルされた本体ではなく、固定長のアセンブラコードの一部であり、どのメソッドにも同じ命令が含まれています。 実際、jmpが発生するアドレスのみが変更されます。 メソッドがコンパイルされる前に、アドレスはこのメソッドのコンパイラを指します(したがって、最初の呼び出しはコンパイルを引き起こします)。 さらに、コンパイルが完了すると、jmpコマンドの引数がコンパイラのアドレスから、既にコンパイルされたターゲットのアドレスに変更されます。 利点は明らかです: プロキシ-同じ命令を含みます。メソッドのグループは、2つのフィールドを持つテーブルと見なすことができます:一方はコードと遷移アドレスで、他方はメソッド呼び出し命令のアドレスを変更しません。





クラスにキャストするとどうなりますか
基本型へのキャスト-何も起こりません、継承されたものへのキャスト-最初に、キャストの可能性がチェックされ、オブジェクトの操作は以前と同じ仮想メソッドのテーブルに従います



型変換は、メモリ内のオブジェクトの構造レベルでほとんど共通点のない言語の構文糖衣です。 オブジェクトは+ SyncBlockIndex + MethodsTablePtrフィールドで構成されているため、MethodsTablePtrがオブジェクトの型の説明へのポインターを担当するため、オブジェクトへのポインターが別の型の変数に置かれても何も起こりません(オブジェクトの型は変更されません)。 追加のチェックが呼び出されると呼び出されます。 コンパイル段階では、上記のタイプが事前にわかりません。 確認する必要があります。 チェックは、メソッドテーブルに移動し、Objectに遭遇する(キャストできない)か、探しているものに等しいポインターが見つかるまでParentClassMethodsTableポインターチェーンを通過することによって行われます。 仮想メソッドの呼び出し方法については、 Wikiで詳しく説明しています。



型がインターフェイスにキャストされるとどうなりますか
型テーブルには、インターフェイスの辞書へのリンクがあり、キャストの可能性を確認するには、すべてをバイパスする必要があります。 基本タイプに行く必要はありません。なぜなら それらはすべて辞書にもあります。 一致が見つかった場合、オブジェクトのタイプではなく、インターフェイスの仮想メソッドのテーブルのアドレスがレジスタにロードされます



インターフェイスは、あるタイプと別のタイプの両方で継承の途中のタイプに現れる可能性があるため、仮想メソッドテーブルを使用した一般的なスキームは機能しません。 代わりに、仮想メソッドテーブルには2番目のテーブル(インターフェイスディクショナリ)へのリンクがあります。 実際、これはそれぞれの仮想メソッドテーブルへのリンクのリストです。 型がキャストされると、必要なテーブルへのポインターの等価性によって検索が実行されるため、必要なテーブルがバイナリ検索メソッドによって検索されます(リストの中で、仮想メソッドテーブルに必要なポインターの存在が検索されます)。 見つかった場合、このテーブルへのポインタがレジスタにロードされ、メソッド呼び出しがそれを通過します(テーブルにはクラス内のメソッドのアドレスが含まれます。したがって、インターフェースの実装ごとに、インターフェースを実装するすべてのクラスとすべてのクラスの子孫のテーブルにメソッドのリストが存在します)およびインターフェース)



暗黙的インターフェイスと明示的インターフェイスの違いは何ですか?
両方ともインターフェイスディクショナリで強調表示されますが、明示的なメソッドはクラスの仮想メソッドのテーブルにはなく、インターフェイスディクショナリにのみあります



実際、暗黙的なインターフェイスのメソッドはクラス継承階層の一部であり、インターフェイスタイプへの変換とは別に呼び出すことができるため、クラスの仮想メソッドのテーブルに存在する必要があります。 ただし、メソッドがクラスから分離されている場合の明示的な実装もあります。 そのようなメソッドは、クラスの仮想メソッドのテーブルには存在しません。 ただし、どちらの場合も、インターフェイスにキャストして操作する権利があります。 そして、これは、それらが両方のタイプのインターフェースのマップに存在し、すべての基本タイプ-インターフェースとともに存在することを意味します。



.Netのストリーム
MS Windowsプラットフォームスレッドであるため、スレッド間の切り替えの価格はWindowsの合計価格に等しい



ここでは、一般的に、コメントはありません。 GCは、マルチスレッドコードを処理する一般的なプロセスでスタックすることはありません。 .Netアプリケーションは通常のWindowsアプリケーションのように動作します



ジェネリック型
JITは、型パラメーターごとに無関係なクラスを作成します



JITはアプリケーションロジックについて何も知ることができないので、
IEnumerable<object> a = new List<int>()
      
      



何とか動作するはずです。 したがって、汎用引数の特定の各セットの実装は、個別のコードにコンパイルされます。



インスタンスメソッドの呼び出し方法-これ
これはメソッドの最初のパラメーターであり、構文糖衣の目的では表示されません



メソッド呼び出しを想像すると、プロセッサレベルでfastcall表記に従って発生します。メソッドの最初の2つのパラメーターはレジスターに、残りはスタックに移動します。 さらに何も転送しないと、メソッド内でどのオブジェクトが呼び出されたのかわからないことがわかります。 状況を修正するために、これを常に最初のパラメーターとして渡しますが、プログラミング言語(C#など)では、プログラマーの希望に関係なく常に存在するローカルthis変数を導入することで、単に表示しません。 これは、実際にはメソッドの最初のパラメーターです。



値と参照タイプ。 違いは何ですか?
値型はスタックとヒープの両方にありますが、参照型はヒープのみにあります。 その値が異なる-値によって送信され、参照-参照によって送信される



インタビューの開発者の大部分は、最初の答えを言っています。 実際、Valueタイプがクラスフィールドの場合、フレームを作成したメソッドを終了すると、そのデータが正しいデータで有効にならないため、値が作業スタック内にないため、これらは適合しません。 クラスフィールド(値型であっても)は常にヒープ上にあります。 値タイプと参照タイプの違いは、コピー時に参照タイプが参照タイプからコピーされ、構造全体が値タイプからコピーされることです。 2番目の違い:ロックされていない値型には、MethodsTableおよびSyncBlockIndexフィールドがありません。



静的変数はどこにありますか?
内部配列に横たわり、配列+インデックスへの参照によりアクセス



これは単なる神聖な知識です。 これで終わりです。



仮想メソッドはどのように呼び出されますか?
JITは、事前に計算されたインデックスを使用して呼び出しが行われる型の仮想メソッドテーブルを作成します

仮想メソッドを継承して持つと、次のようになります。クラスからクラスへ、それらはどこにも消えることなく、ストックでのみ追加できます。 さらに、後続の各クラスでは、すべての基本メソッドのすべてのメソッドが存在することが保証されます。 1つの違いがあります-継承中にメソッドをオーバーライドできます。 したがって、特定のクラスのメソッドのテーブルを作成する場合、基本クラスのメソッドは、基本クラスのテーブルと同じインデックスにある必要があります。 メソッドが再定義されていない場合、テーブル内のメソッド本体のアドレスは、基本クラスのテーブル内のこのメソッドのアドレスと一致します。 メソッドがオーバーライドされると、値は異なります。 基本クラスのすべてのメソッドの後に、現在のクラスのメソッドが配置されます。 呼び出し自体は次のようになります。

  • virtメソッドのテーブルアドレスをダウンロードします。
  • メソッドのリストの先頭に移動します
  • インデックスによってメソッドのアドレスを取得します(たとえば)1
  • 彼を呼び出します。


さらに、継承中はToString()メソッドが常にこの場所にあり、継承者で再定義することもあるため、基本クラスだけでなく継承者もToString()メソッドが呼び出されます。








All Articles