2

私が取り組んでいるプロジェクトは、多数のクラスのコードを生成します-数百から数千が予想されます。これらのクラスのどれだけが実際にアクセスされるかは、生成時にわかりません。

生成されたクラスは、(1)すべてが単一のアセンブリ(または場合によっては少数のアセンブリ)に存在し、つま先を消費するプロセスの開始時にロードされます。

...または(2)Javaがすべてのクラスを単一のバイナリファイルにコンパイルするのと同じように、クラスごと*.classに1つのアセンブリを生成し、必要に応じてアセンブリをロードするメカニズムを考え出すことができます。

質問:どちらの場合がより良い(メモリと時間)パフォーマンスをもたらすでしょうか?

私の直感では、ケース(1)の場合、ロード時間と使用メモリは、単一のモノリシックアセンブリを構成するクラスの数に正比例します。OTOH、ケース(2)には複雑な問題があります。

ロードアセンブリの内部に関連するリソース、特にどのコードが呼び出されるか(もしあれば!?)、どのメモリが割り当てられるか(新しくロードされたアセンブリの簿記)を知っている場合は、それらを共有してください。

4

2 に答える 2

9

存在しない問題を解決しようとしています。アセンブリのロードは、.NET で非常に大幅に最適化されています。

大きなアセンブリを多くの小さなアセンブリに分割することは、間違いなくあなたができる最悪のことです。アセンブリをロードする際の最大の費用は、ファイルを見つけることです。これはコールドスタートの問題です。CLRローダーは低速のディスクによって停止します。ファイルの内容を含むディスクセクターを見つけるには、ディレクトリエントリを取得して検索する必要があります。この問題は、アセンブリデータをファイルシステムキャッシュから取得できるウォームスタートで解消されます。Javaはこの方法でもそれを行わないことに注意してください。それは、.classファイルを.jarにパッケージ化します。.jarは、アセンブリの大まかな同等物です。

ファイルが見つかると、.NETはオペレーティングシステム機能を使用して、アセンブリデータを実際に非常に安価にロードできるようにします。メモリマップトファイルを使用します。これには、ファイル用に仮想メモリを予約するだけで、ファイルからの読み取りは含まれません。

読み取りは後で行われるまで発生せず、ページフォールトによって実行されます。デマンドページング仮想メモリオペレーティングシステムの機能。仮想メモリにアクセスするとページフォールトが発生し、オペレーティングシステムはファイルからデータをロードし、仮想メモリページをRAMにマップします。その後、プログラムは続行されますが、OSによって中断されたことに気付くことはありません。これらのページフォールトを生成するのはジッターであり、アセンブリ内のメタデータテーブルにアクセスして、メソッドのILを見つけます。次に、そこから実行可能なマシンコードを生成します。

このスキームの自動的な利点は、アセンブリ内にあるが使用されていないコードに対して料金を支払う必要がないことです。ジッタには、ILを含むファイルのセクションを調べる理由がないため、実際に読み取られることはありません。

また、このスキームの欠点に注意してください。クラスを初めて使用すると、ディスクの読み取りによるパフォーマンスヒットが発生します。これは何らかの方法で支払う必要があります。.NETでは、債務は可能な限り最後の時点で支払われる必要があります。これが、属性が遅いという評判がある理由です。

大きなアセンブリは、多くの小さなアセンブリよりも常に優れています。

于 2012-11-16T16:10:01.370 に答える
2

どちらの場合でも、(メモリと時間の)パフォーマンスが向上します

コンパイラが多くの最適化を行うことを念頭に置いて、オプション1は間違いなく進むべき道です。クラスごとに個別のアセンブリを用意するのは完全にやり過ぎのようです。それだけでなく、多くの小さなアセンブリよりも1つの大きなアセンブリをロードする方が速いでしょう。

また、これは時期尚早の最適化のように感じます。私のアドバイスは最初の(正気の)オプションに固執し、必要に応じて後でクラスを別々のアセンブリに分割します。

于 2012-11-16T14:06:56.503 に答える