ホームページ  >  記事  >  運用・保守  >  仮想メモリ管理の詳しい説明

仮想メモリ管理の詳しい説明

PHP中文网
PHP中文网オリジナル
2017-06-20 11:23:263432ブラウズ

現代のオペレーティングシステムは一般に仮想メモリ管理(Virtual Memory Management)メカニズムを採用しており、これにはプロセッサ内のMMU(Memory Management Unit)によるサポートが必要です。まず、PA と VA の概念を紹介します。

1.PA (物理アドレス) ---物理アドレス

プロセッサに MMU がない場合、または MMU はあるが有効になっていない場合、CPU 実行ユニットによって送信されたメモリ アドレスが直接プロセッサに送信されます。下図に示すように、チップのピンをメモリチップ(以下、仮想メモリと区別するため物理メモリと呼びます)に渡すことをPA(Physical Address、以下PA)と呼びます。

仮想メモリ管理の詳しい説明

物理アドレス

2.VA (仮想アドレス) ---仮想アドレス

プロセッサで MMU が有効になっている場合、CPU 実行ユニットによって送信されたメモリ アドレスは MMU によってインターセプトされ、CPU 実行ユニットからのアドレスはCPU から MMU への接続は仮想アドレス (以下、VA と呼びます) と呼ばれ、MMU はこのアドレスを別のアドレスに変換して CPU チップの外部アドレス ピンに送信します。つまり、図に示すように、VA を PA にマッピングします。下の図。

仮想メモリ管理の詳しい説明

仮想アドレス

32ビットプロセッサの場合、内部アドレスバスは32ビットでCPU実行ユニットに接続されます(図では4本のアドレス線のみが概略的に描かれています)が、MMU変換後の外部アドレスバスは必ずしも32であるとは限りません-少し。つまり、仮想アドレス空間と物理アドレス空間は独立しています。32 ビット プロセッサの仮想アドレス空間は 4GB ですが、物理アドレス空間は 4GB より大きくても小さくても構いません。

MMUはVAをページ単位でPAにマッピングします。32ビットプロセッサのページサイズは通常4KBです。たとえば、MMU はマッピング項目を通じて VA の 0xb7001000 ~ 0xb7001fff のページを PA の 0x2000 ~ 0x2fff のページにマッピングできます。CPU 実行ユニットが仮想アドレス 0xb7001008 にアクセスする場合、アクセスされる実際の物理アドレスは 0x2008 です。物理メモリ内のページは、物理ページまたはページ フレームと呼ばれます。仮想メモリのどのページが物理メモリのどのページ フレームにマップされるかは、ページ テーブル (ページ テーブル) によって記述されます。ページ テーブルは物理メモリに格納されており、MMU はページ テーブルを検索して、VA がどの PA を使用するかを決定します。にマッピングされます。

3. プロセス アドレス空間

プロセス アドレス空間
仮想メモリ管理の詳しい説明

x86 プラットフォームの仮想アドレス空間は 0x0000 0000~0xffff ffff で、一般的に最初の 3GB (0x0000 0000~0xbfff ffff) がユーザー空間、最後の 1GB (0xc000 0000~0xffff ffff) がカーネル空間です。

テキストセグメントとデータセグメント

  • テキストセグメント、.textセグメント、.rodataセグメント、.pltセグメントなどを含みます。 /bin/bash からメモリにロードされ、アクセス権限は r-x です。

  • データセグメント (.data セグメント、.bss セグメントなどを含む)また、/bin/bash からメモリにロードされ、アクセス権限は rw- です。

ヒープとスタック

  • ヒープ: ヒープとは、単にコンピューターのメモリに残っている領域のことで、ここで malloc 関数が動的にメモリを割り当てます。メモリを動的に割り当てると、ヒープ スペースがより高いアドレスに向かって拡大する可能性があります。ヒープ空間のアドレスの上限は Break と呼ばれ、ヒープ空間を高いアドレスに拡張するには、新しい仮想メモリ ページを物理メモリにマップするために、システム コール brk によって実現されます。また、関数は brk を呼び出してカーネル メモリからの割り当てを要求します。

  • スタック: スタックは特定のメモリ領域であり、高アドレス部分はプロセスの環境変数とコマンドラインパラメータを保存し、低アドレス部分は関数スタックフレームとスタックスペースを保存します。実際のアプリケーションでは大量のメモリを動的に割り当てることは珍しくありませんが、各層には数十の深い関数呼び出しがあるため、明らかにヒープ領域ほどの拡張の余地はありません。の呼び出しに多くのローカル変数が含まれることは非常にまれです。

プログラムを書くときにメモリ割り当てに注意しないと、ヒープやスタックで以下の問題が発生する可能性があります:

  1. メモリリーク: 関数内で malloc を渡す場合ヒープ内にスペースを配置し、それを保存するためにスタック上にポインタ変数を宣言すると、関数が終了すると、ポインタ変数を含む関数のメンバー変数が解放され、スペースは回復されず、回復できません。解放されました。時間が経つと、次のようなメモリ リークの問題が発生する可能性があります。

  2. スタック オーバーフロー: スタックに多すぎるデータ (大きな構造体や配列など) を置くと、「スタック オーバーフロー」問題が発生し、プログラムが終了する可能性があります。この問題を回避するには、そのような変数を宣言するときに、malloc を使用してヒープ領域を適用する必要があります。

  3. ワイルドポインターセグメンテーションフォルト: ポインターが指すスペースが解放されている場合、そのポインターを使用して解放されたスペースにアクセスしようとすると、「セグメントフォルト」の質問が発生します。この時点で、ポインタはワイルド ポインタになっているため、ワイルド ポインタは時間内に手動でクリアする必要があります。

4. 仮想メモリ管理の役割

  1. 仮想メモリ管理は、物理メモリのアクセス許可を制御できます。物理メモリ自体にはアクセスが制限されず、任意のアドレスの読み取りと書き込みが可能ですが、オペレーティング システムでは、異なるページに異なるアクセス権が必要になります。これは、CPU モードと MMU のメモリ保護メカニズムを使用することで実現されます。

  2. 仮想メモリ管理の主な機能は、各プロセスが独立したアドレス空間を持つことができるようにすることです。いわゆる独立したアドレス空間とは、異なるプロセスの同じ VA が MMU によって異なる PA にマッピングされることを意味し、あるプロセスの任意のアドレスにアクセスすると、他のプロセスのデータにアクセスできなくなります。これにより、どのプロセスも不正なメモリアクセスが発生することになります。命令や悪意のあるコードが他のプロセスのデータを誤って書き換えたり、他のプロセスの動作に影響を与えたりすることがないため、システム全体の安定性が確保されます。一方、各プロセスは仮想アドレス空間全体を排他的に所有していると考えるため、各プロセスのアドレス範囲が競合するかどうかを考慮する必要がなく、リンカとローダの実装が容易になります。

プロセスのアドレス空間は独立しています仮想メモリ管理の詳しい説明是独立的

    VAからPAへのマッピングにより、不連続な物理アドレスを持つ複数のメモリブロックを連続したメモリブロックにマッピングすることができます。仮想アドレス。たとえば、malloc を使用して大きなメモリ領域を割り当てたい場合、十分な空き物理メモリはあるものの、十分な連続空きメモリがない場合は、複数の不連続な物理ページを割り当て、それらを連続した仮想ページにマップできます。アドレス範囲。
不連続PAは連続VAにマッピング可能仮想メモリ管理の詳しい説明

  1. システムが同時に多数のプロセスを実行している場合、各プロセスに割り当てられたメモリの合計が、実際に利用可能な物理メモリよりも大きくなる場合がありますが、この場合でも仮想メモリ管理により各プロセスは正常に実行されます。各プロセスには仮想メモリ ページのみが割り当てられるため、これらのページのデータを物理ページにマッピングしたり、物理ページを占有せずにディスクに一時的に保存したりすることができます。ディスク上の仮想メモリ ページは一時的に保存されます。ディスク パーティション、またはスワップ デバイスと呼ばれるディスク ファイルの場合もあります。 物理メモリが十分ではない場合、使用頻度の低い物理ページのデータは一時的にスワップ デバイスに保存されます。その後、その物理ページは空きとみなされ、プロセスに再割り当てされます。このプロセスはスワップ アウト (ページ アウト) と呼ばれます。 )。プロセスがスワップアウトされたページを使用したい場合、スワップ デバイスから物理メモリにロードし直します。これはスワップ イン (ページ イン) と呼ばれます。スワップアウト操作とスワップイン操作はまとめてページングと呼ばれ、次のようになります:

    システムに割り当て可能なメモリの総量=物理メモリのサイズ+サイズ下の図に示すように、スワップ デバイス
の。最初の図はスワップアウトし、物理ページのデータをディスクに保存し、アドレスのマッピングを解除し、物理ページを解放しています。 2 番目の図は、スワップイン、空き物理ページの割り当て、ディスク一時ページのメモリへのロードバック、およびアドレス マッピングの確立を行っています。

仮想メモリ管理の詳しい説明ページ変更

5.mallocとfree

C標準ライブラリ関数mallocは、brkシステムコールを通じてオペレーティングシステムからのメモリに動的にメモリを割り当てることができます。動的に割り当てられたメモリが使い果たされた後、free で解放、より正確には malloc に戻すことができるため、次回 malloc が呼び出されたときにメモリを再度割り当てることができます。

りー

malloc的参数size表示要分配的字节数,如果分配失败(可能是由于系统内存耗尽)则返回NULL。由于malloc函数不知道用户拿到这块内存要存放什么类型的数据,所以返回通用指针void *,用户程序可以转换成其它类型的指针再访问这块内存。malloc函数保证它返回的指针所指向的地址满足系统的对齐要求,例如在32位平台上返回的指针一定对齐到4字节边界,以保证用户程序把它转换成任何类型的指针都能用。

动态分配的内存用完之后可以用free释放掉,传给free的参数正是先前malloc返回的内存块首地址。

示例

举例如下:

 1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 typedef struct { 5     int number; 6     char *msg; 7 } unit_t; 8 int main(void) 9 {10     unit_t *p = malloc(sizeof(unit_t));11     if (p == NULL) {12         printf("out of memory\n");13         exit(1);14     }15     p->number = 3;16     p->msg = malloc(20);17     strcpy(p->msg, "Hello world!");18     printf("number: %d\nmsg: %s\n", p->number, p->msg);19     free(p->msg);20     free(p);21     p = NULL;22     return 0;23 }</string.h></stdlib.h></stdio.h>

 

说明

  • unit_t *p = malloc(sizeof(unit_t));这一句,等号右边是void *类型,等号左边是unit_t *类型,编译器会做隐式类型转换,我们讲过void *类型和任何指针类型之间可以相互隐式转换。

  • 虽然内存耗尽是很不常见的错误,但写程序要规范,malloc之后应该判断是否成功。以后要学习的大部分系统函数都有成功的返回值和失败的返回值,每次调用系统函数都应该判断是否成功。

  • free(p);之后,p所指的内存空间是归还了,但是p的值并没有变,因为从free的函数接口来看根本就没法改变p的值,p现在指向的内存空间已经不属于用户,换句话说,p成了野指针,为避免出现野指针,我们应该在free(p);之后手动置p = NULL;

  • 应该先free(p->msg),再free(p)。如果先free(p),p成了野指针,就不能再通过p->msg访问内存了。

6.内存泄漏

  如果一个程序长年累月运行(例如网络服务器程序),并且在循环或递归中调用malloc分配内存,则必须有free与之配对,分配一次就要释放一次,否则每次循环都分配内存,分配完了又不释放,就会慢慢耗尽系统内存,这种错误称为内存泄漏(Memory Leak)。另外,malloc返回的指针一定要保存好,只有把它传给free才能释放这块内存,如果这个指针丢失了,就没有办法free这块内存了,也会造成内存泄漏。例如:

1 void foo(void)2 {3     char *p = malloc(10);4     ...5 }

foo関数が戻るとき、ローカル変数pのメモリ空間を解放する必要がありますが、それが指すメモリアドレスは失われ、この10バイトは解放できません。メモリ リークのバグは、境界外アクセスなどのプログラム実行エラーを引き起こさないため、発見が困難です。少量のメモリ リークはプログラムの正しい動作に影響を与えません。大量のメモリ リークは、メモリ不足を引き起こします。システム メモリが減少し、頻繁なページ変更が発生し、現在のプロセスに影響を与えるだけでなく、システム全体の速度が低下します。

mallocとfreeに関しては特殊なケースがいくつかあります。 malloc(0) への呼び出しも正当であり、NULL 以外のポインタを返します。このポインタを解放のために渡すこともできますが、このポインタを介してメモリにアクセスすることはできません。 free(NULL) も正当で何も行いませんが、ワイルド ポインタを解放することは違法です。たとえば、最初に malloc を呼び出してポインタ p を返し、次に free(p) を 2 回連続して呼び出すと、次のようになります。ランタイムエラーが発生します。

以上が仮想メモリ管理の詳しい説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。