6

私はカーネルを書いていて、複数のスタックとヒープを仮想メモリに配置する必要があります (そして望んでいます) が、それらを効率的に配置する方法がわかりません。通常のプログラムはどのようにそれを行うのですか?

スタックとヒープは、32 ビット システムによって提供される限られた仮想メモリにどのように (またはどこに) 配置され、可能な限り多くのスペースが確保されるようになっていますか?

たとえば、単純なプログラムがメモリにロードされると、そのアドレス空間のレイアウトは次のようになります。

[  Code  Data  BSS  Heap->  ...  <-Stack  ]

この場合、ヒープは仮想メモリが許す限り (たとえばスタックまで) 大きくなる可能性があり、これがほとんどのプログラムでヒープが機能する方法だと思います。定義済みの上限はありません。

多くのプログラムには、仮想アドレス空間のどこかに配置される共有ライブラリがあります。次に、各スレッドに 1 つずつ、複数のスタックを持つマルチスレッド プログラムがあります。また、.NET プログラムには複数のヒープがあり、そのすべてが何らかの方法で拡張できる必要があります。

すべてのヒープとスタックのサイズに事前定義された制限を設けずに、これがどのように合理的に効率的に行われるかわかりません。

4

2 に答える 2

0

簡単に言えば、システム リソースは常に有限であるため、無制限にすることはできません。

メモリ管理は常に、明確に定義された役割を持つ複数のレイヤーで構成されます。プログラムの観点からは、アプリケーション レベルのマネージャーが表示されます。通常は、それ自体に割り当てられた単一のヒープのみに関係します。上記のレベルでは、(その) 1 つのグローバル ヒープから必要に応じて複数のヒープを作成し、それらをサブプログラム (それぞれが独自のメモリ マネージャーを持つ) に割り当てることができます。それを超えると、標準malloc()/free()使用される可能性があり、それらを超えるオペレーティングシステムは、ページとプロセスごとの実際のメモリ割り当てを処理します(基本的に、複数のヒープだけでなく、ユーザーレベルのヒープも一般的に関係ありません)。

メモリ管理にはコストがかかり、カーネルへのトラップも同様です。この 2 つを組み合わせると、パフォーマンスに深刻な打撃を与える可能性があるため、アプリケーションの観点から実際のヒープ管理と思われるものは、実際にはパフォーマンスのためにユーザー空間 (C ランタイム ライブラリ) に実装されます (その他の理由は今のところ範囲外です)。 )。

共有 (DLL) ライブラリをロードするとき、それがプログラムの起動時にロードされる場合、当然のことながら CODE/DATA/etc にロードされる可能性が最も高いため、ヒープの断片化は発生しません。一方、実行時にロードされる場合は、ヒープ領域を使い果たす以外にほとんどチャンスはありません。もちろん、スタティック ライブラリは単純に CODE/DATA/BSS/etc セクションにリンクされています。

結局のところ、オーバーフローしないようにヒープとスタックに制限を課す必要がありますが、他のものを割り当てることができます。その制限を超えて成長する必要がある場合は、次のいずれかを実行できます

  • アプリケーションをエラーで終了する
  • メモリマネージャにそのスタック/ヒープのメモリブロックを割り当て/サイズ変更/移動させ、おそらく後でヒープ(独自のレベル)を最適化します。そのためfree()、通常はパフォーマンスが低下します。

call平均としてかなり大きい 1KB のスタック フレームを考慮すると(アプリケーション開発者が経験の浅い場合に発生する可能性があります)、10240 個のネストされたcall-s には 10MB のスタックで十分です。ところで、それ以外に、スレッドごとに複数のスタックとヒープはほとんど必要ありません。

于 2013-04-25T11:12:58.173 に答える