Linuxでのプロセスアドレス空間(初心者に必要)

コンテンツ

1.プログラムアドレス空間

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


1.プログラムアドレス空間

まず、画像を通してc /c++のプログラムアドレス空間を確認しましょう。

 これらの分野の簡単な紹介は次のとおりです。

1.ヒープ領域:

ヒープデータ領域はヒープ領域です。Cプログラムでは、この領域の割り当てと回復はとによって実行されmallocますfreeエリア割り当てが進むにつれて、エリアは下位アドレスから上位アドレスに拡張し続けます。

2.スタック領域:

スタック領域は、プログラムの実行時に、関数呼び出しによって生成されたスタックがこの領域に格納されます。この領域の開始アドレスは固定されており(カーネルメモリ領域の隣)、関数を呼び出すときにスタックが生成されるため、この領域は上位アドレスから下位アドレスに拡張され続けます。

3.コードとデータ領域:

実行可能プログラムファイルの内容は、この領域にロードされ、2つの部分に分割されます。下位アドレス部分には、プログラムコードと、読み取り専用部分である読み取り専用データが含まれ、他の領域には、読み取りと書き込みが可能な領域が格納されます。読み取り専用部分である実行可能ファイルのデータ。読み取りおよび書き込み領域。

4.カーネルメモリ領域:

仮想アドレス空間の最上位アドレスにあるアドレス空間のブロック内のカーネル仮想メモリ領域。ユーザープロセスはこの領域にアクセスできません。

タイトルは、上の図のアドレス空間セグメントを簡単な表現で確認します。

#include<stdio.h>                                                                                                                                           
  2 #include<iostream>
  3 using namespace std;
  4   int g_unval;
  5  int g_val=0;
  6  int main()
  7  {
  8    printf("code addr:%p\n",main);//打印代码区的地址
  9    const char*str="ddddddd";
 10    printf("string rdonly addr %p\n",str);//打印字符常量区的地址
 11    //打印未初始化全局数据区的地址
 12    printf("uninit addr: %p\n",&g_unval);
 13    //打印已初始化全局数据区
 14    printf("init addr: %p\n",&g_val);
 15   //打印堆区的地址 
 16      int *p1=new int (1);
 17      int *p2=new int(2);
 18      int *p3=new int(3);
 19     printf("heap addr: %p \n",p1);
 20     printf("heap addr: %p \n",p2);
 21     printf("heap addr: %p \n",p3);
 22 
 23 
 24    //打印栈区的地址
 25    int a1=10;
 26    int a2=20;
 27    int a3=30;
 28    printf("stack addr : %p\n",&a1);
 29    printf("stack addr : %p\n",&a2);
 30    printf("stack addr : %p\n",&a3);
 31 
 32    return 0;
 33 }
~

許可された結果:

 ブランチは確かにこのようなものであることがわかりました。

実験してみましょう:

#include<unistd.h>
  2 #include<stdio.h>
  3 #include<sys/types.h>
  4 int g_val=10;
  5 int main()
  6 {
  7   pid_t id=fork();
  8   if(id<0)
  9   {
 10     printf("fork fail");
 11   }
 12   else if(id==0)
 13   {
 14    while(1)
 15    {
 16     printf(" I am a child pid:%d  g_val:%d &g_val:%p\n",getpid(),g_val,&g_val);
 17     sleep(2);
 18    }
 19 
 20   }
 21   else
 22   {
 23     while(1)
 24     {
 25       printf("I am a parent pid:%d  g_val :%d &g_val:%p\n",getpid(),g_val,&g_val);                                                                          
 26       sleep(2);
 27     }
 28 
 29   }
 30 
 31   return 0;
 32 }
 33 

このコードを実行してみましょう:

 子プロセスと親プロセスによって出力されるg_valと&g_valは同じです。問題ありません。これは前に述べたものと同じです。親プロセスと子プロセスのコードとデータは共有されます(変更)問題ありません。コードを見てみましょう。:

#include<unistd.h>
  2 #include<stdio.h>
  3 #include<sys/types.h>
  4 int g_val=100;                                                                                                                                              
  5 int main()
  6 {
  7   pid_t id=fork();
  8   if(id<0)
  9   {
 10     printf("fork fail");
 11   }
 12   else if(id==0)
 13   {
 14     int cnt=0;
 15    while(1)
 16    {
 17      cnt++;
 18      if(cnt==3)
 19      {
 20        g_val=10;
 21        printf("子进程修改g_val\n");
 22      }
 23     printf(" I am a child pid:%d  g_val:%d &g_val:%p\n",getpid(),g_val,&g_val);
 24     sleep(2);
 25    }
 26 
 27   }
 28   else
 29   {
 30     while(1)
 31     {
 32       printf("I am a parent pid:%d  g_val :%d &g_val:%p\n",getpid(),g_val,&g_val);
 33       sleep(2);
 34     }
 35 
 36   }
 37 
 38   return 0;
 39 }
 40 
                                                                              
                                              

このプログラムを実行してみましょう:

 子プロセスがg_valの値を変更した後、プロセスが独立しているため、コピーオンライトが発生することがわかりました。子プロセスと親プロセスによって出力される値が異なることは理解できますが、驚いています。それらのアドレスが同じであることを確認します。これが物理アドレスである場合、同じスペースではなく同じスペースからコンテンツを取得するにはどうすればよいでしょうか。だから私たちは得ることができます:

これは間違いなく物理アドレスではありません。Linuxアドレスでは、この種のアドレスは仮想アドレスと呼ばれます。C/ C ++言語で表示されるアドレスは、すべて仮想アドレスです。物理アドレスはユーザーには見えず、OSによって管理されます。

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

したがって、「プログラムのアドレス空間」は正確ではなく、プロセスのアドレス空間である必要があると前に述べました。プロセスアドレス空間はOSによって作成された構造体です。タイトルはmm_structと呼ばれます。仮想アドレス空間は分割されます。その仮想アドレスは(0x 00 000000からoxffffff ff)までで、同じ他のプロセスによって管理されます。制御ブロックPCB。独自のプロセスアドレス空間。つまり、各プロセスは、それが排他的リソースであると見なし、4GBの領域(32ビットプラットフォームの下)があると見なします。したがって、プロセスアドレス空間は実際には仮想アドレス空間です。仮想アドレス空間は、領域がアドレス空間で分割されている場合、対応する線形位置の仮想アドレスと見なすこともできます。

仮想アドレス空間各プロセスには仮想アドレス空間があり、OSは特定のマッピング関係を介して仮想アドレスを物理アドレスにマッピングします。これにより、実際の物理アドレスに対応します。

 そして、この変換作業は伝説的なページテーブルです。上記の現象を以下に説明します。子プロセスの作成では親プロセスをテンプレートとして使用するため、親プロセスと子プロセスには仮想アドレス空間があり、内容は基本的に同じ(データの一部が異なる)であり、ページテーブルのマッピング関係は子です。プロセスは親プロセスと同じです。子プロセスがデータを変更すると、OSは子プロセスを中断して、データをコピーするための新しいスペースを開き、子プロセスを許可します。プロセスは、新しく開いたスペースを変更します。物理アドレスは変更されましたが、仮想アドレスは変更されていません。これは、子プロセスの仮想アドレスと物理アドレスの間のマッピング関係を変更するためです。したがって、前に見たアドレスが本質的に同じである場合、仮想アドレスは同じです。

 これで、親プロセスと子プロセスがどのように独立しているかを理解できます。親子プロセスのコードとデータは共有されますが、一方の当事者がそれに書き込もうとすると、コピーオンライトも実行され、ページテーブルのマッピングと物理メモリの関係が変更されます。親子プロセスには独自のデータがあり、独立性を実現します

なぜこのように設計されているのですか?

理由1:

仮想アドレス空間では、物理メモリにアクセスするプロセスが物理メモリに直接アクセスすることはできず、メモリ管理の操作に役立つ中間層(ページテーブル)が追加されます。このように、各プロセスは仮想アドレス空間とページテーブルを介して対応する物理メモリにアクセスする必要があります。オペレーティングシステムは、仮想アドレスを物理アドレスに変換するときに介入して、変換後に正当な物理アドレスであるかどうかを判断できます。物理メモリを保護します。

理由2:

メモリアプリケーションとメモリ使用量の概念は時間的に明確に分割されており、基盤となるアプリケーションの一連の操作は仮想アドレス空間によって保護されているため、OSはメモリとプロセスをより適切に管理できます。

理由3:

仮想アドレス空間を使用すると、各プロセスは独自の排他的メモリリソースを考慮し、同じ方法でメモリを表示します。これにより、OSの管理効率が大幅に向上します。

例:CPUがコードを実行するとき、最初にプログラムの開始位置、つまり開始アドレスを見つける必要があります。仮想アドレス空間では、固定仮想アドレスを見つけるだけで済みます。プロセスアドレス空間プロセスごとにマッピング関係が異なるため、この固定仮想アドレスはプロセスごとに異なる物理アドレスにマッピングされ、プロセス関連のコードとデータが検索されるため、CPUはプログラムの開始位置をすばやく見つけることができます。

理由4:

仮想アドレス空間は、アドレスを隣接させ、異常なアクセスや範囲外の可能性を減らすことができます。

プロセスとプロセスの作成を再理解します。

1.プロセスとは何ですか?プロセスは、コード、データ、およびそのためにOSによって作成されたデータ構造(PCB(task_struct)+ mm_struct(プロセスアドレス空間)+ページテーブル)を含むメモリにロードされるプログラムです。PCBから対応するmm_structを見つけることができます。 。

おすすめ

転載: blog.csdn.net/qq_56999918/article/details/123938638