9

私が取り組んでいる OS 用のカーネル (実際には「コア」と呼んでいますが、基本的には同じです) の設計に取り組んでいます。マルチタスキングやメモリ管理などの基本的なことができなければ、OS 自体の詳細は関係ないので、まずはそこから取り組む必要があります。malloc ルーチンの設計について質問があります。

malloc() はカーネル自体の一部 (私はこれに傾倒しています) またはプログラムの一部になると考えていますが、C 標準ライブラリの独自の実装を作成する必要があります。というわけで、malloc を書きます。この点に関して、私の質問は実際にはかなり単純です。C (または C++) はそのヒープをどのように管理しますか?

私が理論の授業でいつも教えられてきたのは、ヒープは指定されたアドレスから始まり、多くの意味でスタックのように振る舞うメモリの断片であるということです。このようにして、グローバルスコープで宣言された変数が最初にあり、それぞれのスコープで宣言されると、より多くの変数がヒープに「プッシュ」され、スコープ外に出る変数は単にメモリ空間に残されることがわかります。ただし、そのスペースは空きとしてマークされているため、必要に応じてヒープをさらに拡張できます。

私が知る必要があるのは、C がこのように動的に拡大するヒープを実際にどのように処理するのかということです。コンパイルされた C プログラムは、malloc ルーチンへの独自の呼び出しを行い、独自のヒープを処理しますか? それとも、自動的に拡張するスペースを提供する必要がありますか? また、C プログラムはヒープの開始位置をどのように認識していますか?

ああ、同じ概念が他の言語にも当てはまることは知っていますが、私はその言語に最も慣れているので、例を C/C++ にしたいと思います。スタックなど他のことも気にしないようにしたいと思います。このようなことは自分で処理できると思います。

したがって、私の本当の質問は、malloc/free (ページ自体の取得と解放などを処理する) 以外に、プログラムは OS が他に何かを提供する必要があるのでしょうか?

ありがとう!

EDIT mallocルーチン自体の実際の動作よりも、Cがヒープに関連してmallocを使用する方法に興味があります。それが役立つ場合、私はこれを x86 で実行していますが、C はクロス コンパイラであるため、問題にはなりません。^_^

さらに編集:用語が混乱している可能性があることを理解しています。「ヒープ」は、プログラムがグローバル/ローカル変数などを格納する場所であると教えられました。私はアセンブリ プログラミングで「スタック」を扱うことに慣れていましたが、代わりにおそらくそれを意味していることに気付きました。私のちょっとした調査によると、「ヒープ」は、プログラムがそれ自体に割り当てた合計メモリ、または OS が提供したメモリのページの合計数 (および順序) を指すのによく使用されます。

それで、それを念頭に置いて、拡大し続けるスタックにどのように対処すればよいでしょうか? (私の C 理論の授業は軽度の... 欠陥があったようです。)

4

7 に答える 7

16

malloc通常、ユーザー空間の C ランタイムに実装され、仮想メモリのページにマップする特定の OS システム コールに依存します。mallocandの仕事はfree、サイズが固定されているメモリのページ (通常は 4 KB ですが、場合によってはそれ以上) を管理し、それらをアプリケーションが使用できる断片にスライス アンド ダイスすることです。

たとえば、GNU libc実装を参照してください。

より単純な実装については、昨年のMIT オペレーティング システムクラスを参照してください。具体的には、最終的なラボ配布資料を参照し、 を参照してくださいlib/malloc.c。このコードは、クラスで開発されたオペレーティング システム JOS を使用します。その仕組みは、マップされていない仮想アドレス範囲を探して、ページ テーブル (OS によって読み取り専用で提供される) を読み取ることです。次に、システム コールsys_page_allocsys_page_unmapシステム コールを使用して、ページを現在のプロセスにマップおよびマップ解除します。

于 2008-10-12T22:03:01.730 に答える
14

問題に取り組むには複数の方法があります。

ほとんどの場合、C プログラムには独自の malloc/free 機能があります。それは小さなオブジェクトで機能します。最初に (そしてメモリが使い果たされるとすぐに) メモリ マネージャは OS にメモリの追加を要求します。これを行う従来の方法は、UNIX バリアントの mmap と sbrk です (Win32 の GlobalAlloc / LocalAlloc)。

メモリ プロバイダー (OS など) の観点から、 Doug Lea メモリ アロケータ(google: dlmalloc)を参照することをお勧めします。そのアロケーターは非常に優れたものであり、すべての主要なオペレーティング システム用のフックを備えています。高性能アロケーターが OS に期待するものを知りたい場合は、これがコードです。

于 2008-10-12T21:40:18.420 に答える
4

ヒープとスタックを混同していませんか?

「拡大し続けるメモリ」、スコープ、変数が宣言されているときにヒープに変数をプッシュすることに言及しているのでお願いします。あなたが実際にスタックについて話しているように聞こえます。

最も一般的な C 実装では、次のような自動変数の宣言

int i;

一般に、i がスタックに割り当てられることになります。一般に、malloc は、明示的に呼び出さない限り、または何らかのライブラリ呼び出しによって呼び出されない限り、関与しません。

C プログラムが通常どのようにスタックとヒープを操作するかについての背景については、Peter Van Der Linden による「Expert C Programming」を参照することをお勧めします。

于 2008-10-12T22:17:23.417 に答える
1

仮想メモリ管理 (ページング) について読んでください。これは非常に CPU 固有であり、すべての OS は、サポートされているすべての CPU に対して特別に VM 管理を実装しています。x86/amd64 用の OS を作成している場合は、それぞれのマニュアルをお読みください。

于 2008-10-13T05:38:28.533 に答える
1

必須の読書: Knuth - Art of Computer Programming、第 1 巻、第 2 章、セクション 2.5。それ以外の場合は、Kernighan & Ritchie の「The C Programming Language」を読んで実装を確認できます。または、Plauger の「The Standard C Library」を読んで別の実装を確認することもできます。

コア内で行う必要があることは、コア外のプログラムが見るものとは多少異なると思います。特に、プログラムのコア内メモリ割り当ては仮想メモリなどを処理しますが、コード外のプログラムは単にコアが提供した結果を見るだけです。

于 2008-10-12T23:50:04.447 に答える
0

デンジャーデンジャー!! カーネル開発を試みることを検討している場合でも、リソースのコストとその可用性が比較的限られていることを十分に認識しておく必要があります...

再帰についての 1 つのことは、(少なくともカーネルの世界では) 非常にコストがかかることです。単純に継続するように記述された多くの関数を目にすることはありません。そうしないと、カーネルがパニックに陥ります。

ここで私の主張を強調するために (stackoverflow.com heh で)、カーネル スタック オーバーフローに関するNT Debugging ブログのこの投稿を確認してください。具体的には、

· x86 ベースのプラットフォームでは、カーネル モード スタックは12Kです。

· x64 ベースのプラットフォームでは、カーネル モード スタックは24Kです。(x64 ベースのプラットフォームには、AMD64 アーキテクチャを使用するプロセッサと Intel EM64T アーキテクチャを使用するプロセッサを搭載したシステムが含まれます)。

· Itanium ベースのプラットフォームでは、カーネル モード スタックは32Kで、 バッキング ストアは32Kです。

それは本当にたくさんではありません。

いつもの容疑者


1. スタックを自由に使用する。

2. 関数を再帰的に呼び出す。

このブログを少し読んでみると、かなり独特な一連の問題を抱えたカーネル開発がいかに困難であるかがわかります。あなたの理論の授業は間違っていませんでした。単純で単純でした。;)

理論から言えば -> カーネル開発は、可能な限り重要なコンテキストスイッチです (おそらく、ミックス内のハイパーバイザーの相互作用をいくらか節約できます!!)。

とにかく、あなたの期待を仮定、検証、テストしないでください。

于 2009-07-14T06:40:36.803 に答える
0

一般に、C ライブラリは の実装を処理し、必要に応じmallocて (anonymousmmapまたは古いシステムでは のいずれかを介してsbrk) OS からメモリを要求します。したがって、カーネル側は、これらの手段のいずれかを介してページ全体の割り当てを処理する必要があります。

次にmalloc、空きメモリをあまり断片化しない方法でメモリを解放します。ただし、私はこれの詳細についてはあまりよく知りません。ただし、アリーナという用語が思い浮かびます。参考文献を見つけることができれば、この投稿を更新します。

于 2008-10-12T21:38:04.120 に答える