3

通常はメモリ サイズが大きいことに気付きます。私が作成したアプリの 1 つは、50 行未満を使用し、WebRequest のみを使用して一連のファイルをダウンロードするだけのコンソール アプリです。自明ではない別のアプリ (mysql、dls、マルチスレッド、100 項目のリストボックス)。最初のものは 21 MB (デバッグ、IDE) を使用し、もう 1 つは 39 MB (デバッグ、IDE) を使用します。また、別のアプリが私のサイトを (これも WebRequest を使用して) ポーリングして、トレイにあるステータス更新を取得し、26mbs (リリース、ide を介して実行されない) を使用して通知します。

なぜこれらはとても高いのですか?上記のC++アプリをcurlを使用して2mb未満で実行したことを知っています。最大のC++ prjは11mbで、100kbのdllと200kbのバイナリをロードします(win32アイコンとサウンドでdirectxを使用)。C# コードをコンパイルして、よりスペースにやさしい方法を教えてください。これらを 128 または 256 MB の RAM しか搭載していないサーバーにデプロイしたいのですが、これらのアプリのいくつかはそれを強制終了します。

サイト ノート: 言及された最初のアプリ (コンソール DLer) をリリース モードで (そして ide を介して) 実行したところ、32 MB に跳ね上がりました。どうして!?!それはもっと紛らわしいです。

4

4 に答える 4

5

正直なところ、メモリ サイズが問題を引き起こしているケースを測定できるようになるまでは、マネージ コードのフット プリントについて心配する必要はありません。.NET アセンブリを起動するときに CLR が実行するさまざまな処理が行われているため、ここにはリストしきれませんが、http://weblogs.asp.net/pwilson/archive/2004/02/14/73033を参照してください。 .aspxおよびその他の多くのリソースについては、http://geekswithblogs.net/sdorman/archive/2008/09/14/.net-memory-management-ndash-resources.aspx を参照してください

この記事を見て、アプリケーションがメモリに関して実際に何を使用しているかを判断する方法についての洞察を得ることができます。 html

マネージ コードを捨てる必要があるよりも少ないメモリでタスク マネージャーにアセンブリを表示したい場合。ごまかす方法は、アプリケーションを.NET アセンブリではなくネイティブ実行可能ファイルにするSalamander Protectorのようなものを使用してアプリケーションをコンパイルすることです。

于 2009-11-27T04:09:22.617 に答える
3

小さな .NET アプリケーションは、いくつかの理由から、メモリ フットプリントに関しては C/C++ アプリケーションと実際には競合できません。

.NET ランタイムは、ネイティブ アプリの起動に必要なものに比べて巨大です。.NET アプリを実行するには、CLR がメモリ内にある必要があります。JIT コンパイラーや GC などのコンポーネントをロードする必要があるだけでなく、多数の内部データ構造も必要です。たとえば、最も単純な .NET アプリケーションでさえ、3 つの AppDomains を持ちます。2 つは CLR によって内部的に使用され、1 つはアプリケーション自体に使用されます。

さらに、アセンブリは参照時に読み込まれます。メソッドは必要になるまでジットされませんが、アセンブリ自体はロード時に大量のアドレス空間を使用します。ある時点でコードが jit されると、ネイティブ コードとしてもう一度メモリに格納されます。したがって、本質的にコンパイルされたコードは .NET アプリに 2 回存在します。

最後に、型システムは、C/C++ アプリで見られるものと比較して、.NET でより精巧です。すべてのオブジェクトには、そのタイプに関する情報が含まれています。これにより、リフレクションやその他の便利な機能が可能になりますが、代償が伴います。

非常に小さいフットプリントが必要な場合は、.NET で十分かもしれませんが、ランタイムのオーバーヘッドが発生するため、最も明白な選択肢ではありません。

また、この関連する質問を参照してください。.NET アプリケーションのメモリ使用量を削減しますか?

于 2009-11-27T05:37:24.433 に答える
2

私は CLR の専門家ではありませんが、CLR はチャンクでメモリを割り当て、アプリケーションがそれほど多くのメモリを使用しない場合でも、非常に高く膨らむ可能性があることに気付きました。そのようなものは、CLRが必要のないメモリを保持するのが好きなので、ウィンドウを呼び出して再割り当てする必要がありません。

アプリケーションのプライベート バイトを確認します。プライベート バイトは、CLR が保持している量よりも、実際に使用しているメモリのより合理的な指標である必要があります。また、プロセスの MaxWorkingSet を設定すると、タスク マネージャーの統計が魔法のように再調整されるようです。

System.Diagnostics.Process loProcess = System.Diagnostics.Process.GetCurrentProcess();
loProcess.MaxWorkingSet = loProcess.MaxWorkingSet;

上記のコードは、TheDailyWtf の候補のようです。笑

于 2009-11-27T04:14:07.690 に答える
0

心に留めておくべきことの 1 つは、ガベージ コレクターは、他の何かが必要になるまで常にメモリを解放するとは限らないということです。したがって、アプリケーションが 100MB のメモリを使用していると主張していても、実際には 50MB を使用している可能性がありますが、ガベージ コレクターにはまだ残りを収集して解放する理由がありません。

アプリケーションの基本的な初期化でも大量の一時ファイルが作成されるため、CLR はアプリケーションにメモリ ブロックを割り当てます。システムに十分なメモリがある限り、ガベージ コレクションは未使用のメモリの検出とクリーンアップをかなり怠ります。これは速度の最適化です。システムがより多くのメモリを必要とし始めると、ガベージ コレクションが開始され、より深いスキャンが開始されます。

ガベージ コレクターを手動で呼び出していないことを確認してください。頻繁に呼び出されるほど、より多くのオブジェクトがより高い世代にプッシュされ、システムのメモリが少なくなるまで収集されません。

于 2009-11-27T04:22:03.870 に答える