2017-05-09 19 views
2

私の質問がLinuxであるかOSに依存しないかはわかりません。プロセスが仮想memを共有する方法(Linux)

実行中のプロセスが3つ(P0、P1、P2と呼びましょう)していて、同時に実行されているように見える場合、どうやって共有しますか?

それぞれが独自のスタック、ヒープなどを維持していますか?内にユーザスペースがありますか?

Scenario A

それとも、単にそれを次の工程に沿って来るまでなどスタック全体、ヒープを、所有して横取りしますか?

Scenario B

みんなありがとう!

+1

ここをクリックしてください:https://www.softprayog.in/programming/interprocess-communication-using-posix-shared-memory-in-linux –

+2

シナリオAのように、物理的なコンピュータのメモリが使用されます。物理アドレスを参照してください。各プロセスには独自の仮想アドレス空間があり、CPUは各メモリアクセス時に仮想アドレスを物理アドレスに変換します。プロセスの競争のポイントから、シナリオBのようにアドレス空間全体を使用できるかのように見えます。参照:http://stackoverflow.com/questions/22290347/understanding-virtual-address-virtual-memory-and -ページング – Marian

答えて

4

Linuxおよびその他の現在使用されているほとんどの汎用オペレーティングシステムでは、メモリはまったく単一のリニアアレイではありません。ページのレベルでvirtual memoryを使用して管理されます。

基本的に、各プロセスには独自の仮想アドレス空間があります。そのほとんどは空でマッピングされておらず、アクセスしようとするとsegmentation faultまたは一般的な保護違反が発生し、通常はプロセスが終了します。プロセスは、カーネルが明示的にプロセスにアクセス可能に設定したメモリにのみアクセスできます。

ほとんどの場合、プロセスはカーネルメモリに直接アクセスすることもできません。例えば、ファイルやデバイスを開く、または読み書きするなどのシステムコールを実行するために、プロセッサコアは実質的にカーネルモードにcontext switchを実行します。カーネルモードでは、カーネルデータ構造と、現在のプロセスで使用されているメモリ同時にアクセス可能です(ただし、必ずしもユーザ空間と同じカーネル空間の仮想アドレスではありません)。

これは、各プロセスにアクセス可能なメモリは、今日、実際には非常に散乱し、不連続であることを意味します

╔════════╗ ╔════════╗ ╔═══════╗ 
    ║ Code ║ ║ Data ║ ║ Stack ║ 
    ╚════════╝ ╟────────╢ ╚═══════╝ 
    ╔════════╗ ║ BSS ║ 
    ║ ROdata ║ ╟────────╢ 
    ╚════════╝ ║ Heap ║ 
    ╔════════╗ ╚════════╝ 
    ║ Libs ║ 
    ╚════════╝ 

アドレス空間のランダム化を使用している場合は、上記の各セグメントのアドレスが一つでも実行から異なる場合があり次へ。通常、コード(読み取り専用および実行可能)と読み取り専用データは固定アドレスにロードされますが、動的にリンクされるライブラリ、スタック、およびデータのアドレスは異なります。

上記のいずれかが別のアドレスよりも高いか低いアドレスを持つべき理由もないので、私は意図的に1つの列ではなく隣り合わせで描画します。

初期化されたデータと初期化されていないデータは、通常、実行可能ファイル(データセクション)から初期化されたデータ部分のみをロードする連続セグメントにあります。 UnixとPOSIXのようなシステムでは、ヒープは初期化されていないデータに従います(brk()またはsbrk()システムコールを使用して展開できます)。 LinuxのようなPOSIXシステムや他のほとんどのシステムでは、プロセスは(匿名の​​)メモリマップを介して追加の "ヒープ"を持つことができます。

プロセスの最初のスレッドも別のスタックセグメントを取得します。追加のスレッドでも独自のスタックが作成されます。

(通常、POSIXスレッドを使用する方法は、プロセスが作成できる同時スレッド数を調べることです。Linuxの典型的な結果はわずか百から二百であり、多くの学習者はこれが非常に奇妙であると感じています。そのような低い数値の理由は、実際には現在のGNU/Linuxデスクトップディストリビューションでは8メガバイトのようなデフォルトのスタックサイズです。 100スレッドのスタックだけではほぼ1ギガバイトのメモリが必要となるため、同時スレッドの数は主にそのスタックで使用できるメモリによって制限されます。非再帰的なスレッドワーカー関数はたかだか数十キロバイトのスタックしか必要とせず、新たに作成されたpthreadのスタックサイズを明示的に設定するために数行のコードが必要です。単一プロセス内の同時スレッドの最大数は、通常、システム管理者が設定したプロセス制限またはデフォルトの配布に応じて、通常1000以上のオーダーです。

上記の図には、「OS」はありません。

実際には、「オペレーティングシステム」を2つの完全に別個の部分、すなわちsystem callsに実装されている機能を提供するカーネルと、システムコールインターフェイス以外のインターフェイスを実装するライブラリに分割する必要があります。ユーザー空間プロセッサー、通常は標準Cライブラリーから開始します)。

は、私は上記のみボックス(ライブラリ用)1「Libsの」を描きましたが、実際には、各ライブラリのコードは、メモリの自分の別のセグメントを取得する傾向があります。

Linuxの特定の例を見てみましょう(これは私が今使っているものですから)。 catコマンドLinuxでは、/sys/procのファイルシステムは特別な擬似ファイルシステムツリーであり、記憶媒体上のファイルには全く対応していませんが、アクセスされるたびにカーネルによって構築されます - 本質的にカーネル提供のリアルタイムビューですカーネルが知っているデータの数。 /proc/selfサブツリーには、 "現在のプロセス"に関する情報が含まれています。つまり、そのプロセスがそのディレクトリを調べているプロセスです。 (複数のファイルを同時に調べても、それは通常のファイルシステムではなく、カーネルで作成され、必要に応じて提供されるため、それぞれ独自のデータしか表示されません)。/proc/self/mapsプロセスIDがPIDのプロセスの場合は/proc/PID/maps)pseudo-fileは、プロセスが持つすべてのメモリマッピングを記述します。 cat /proc/self/mapsを実行すると、catプロセス自体のマッピングがわかります。私のマシン(x86-64のアーキテクチャ上で実行されている64ビットLinux)上では、

00400000-0040c000 r-xp 00000000 08:05 2359392    /bin/cat 
0060b000-0060c000 r--p 0000b000 08:05 2359392    /bin/cat 
0060c000-0060d000 rw-p 0000c000 08:05 2359392    /bin/cat 
0215f000-02180000 rw-p 00000000 00:00 0     [heap] 
7f735b70f000-7f735c237000 r--p 00000000 08:05 658950  /usr/lib/locale/locale-archive 
7f735c237000-7f735c3f6000 r-xp 00000000 08:05 1179825  /lib/x86_64-linux-gnu/libc-2.23.so 
7f735c3f6000-7f735c5f6000 ---p 001bf000 08:05 1179825  /lib/x86_64-linux-gnu/libc-2.23.so 
7f735c5f6000-7f735c5fa000 r--p 001bf000 08:05 1179825  /lib/x86_64-linux-gnu/libc-2.23.so 
7f735c5fa000-7f735c5fc000 rw-p 001c3000 08:05 1179825  /lib/x86_64-linux-gnu/libc-2.23.so 
7f735c5fc000-7f735c600000 rw-p 00000000 00:00 0 
7f735c600000-7f735c626000 r-xp 00000000 08:05 1179826  /lib/x86_64-linux-gnu/ld-2.23.so 
7f735c7fe000-7f735c823000 rw-p 00000000 00:00 0 
7f735c823000-7f735c825000 rw-p 00000000 00:00 0 
7f735c825000-7f735c826000 r--p 00025000 08:05 1179826  /lib/x86_64-linux-gnu/ld-2.23.so 
7f735c826000-7f735c827000 rw-p 00026000 08:05 1179826  /lib/x86_64-linux-gnu/ld-2.23.so 
7f735c827000-7f735c828000 rw-p 00000000 00:00 0 
7ffeea455000-7ffeea476000 rw-p 00000000 00:00 0   [stack] 
7ffeea48b000-7ffeea48d000 r--p 00000000 00:00 0   [vvar] 
7ffeea48d000-7ffeea48f000 r-xp 00000000 00:00 0   [vdso] 
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall] 

最初の3つのものは、コード(r-xp)、読み出し専用データ(r--p)であり、(rw-p)のデータを初期化示しプロセス自体のために。プロセスはsbrk()を使用して拡張することができることをデータセグメント(または「ヒープ」)は、第1(すなわち、sbrk(0)0x60d000を返す。)である

プロセスは、最大アドレス0x215f000から適切ないくつかのヒープを有している(ただし0x2180000を含む)。

次のセグメントは、現在のロケールデータの読み取り専用マッピングです。 Cライブラリは、これをロケール対応のインタフェースに使用します。 Cライブラリ(---p)によって必要とされるコード(r-xp)、何とか用いる通常アクセスできないマッピング/、読み取り専用データ(r--p)、および初期化されたデータ(rw-p):

次の4つのセグメントは、Cライブラリ適切です。

保護モード(rw-p)と次のセグメント、および最後の列にない名前を持つ他のセグメントは、別のデータセグメントまたはヒープです。

次の3つのセグメントは、Linuxで使用されているダイナミックリンカ、ld.soです。ここでも、コードセグメント(r-xp)、読み取り専用データセグメント(r--p)、初期化データセグメント(rw-p)があります。

[stack]セグメントは、最初のスレッドのスタックです。 (catはシングルスレッドなので、スレッドは1つしかありません)[vvar]セグメントは、カーネルによって提供されます(プロセスが、システムコールのオーバヘッドを招くことなく、カーネルが提供する特定のデータに直接アクセスできるようにします)。 [vdso][vsyscall]セグメントは、完了するために完全なコンテキストスイッチを必要としない、システムコールを高速化するためにカーネルによって提供されます。

このように、完全な画像は断片化されていますが、古いCやオペレーティングシステムの書籍よりも自由な形で自由に表示されます。

関連する問題