私は2つのソース、つまりプロセスのメモリレイアウトのメモリマッピングセグメントから共有メモリセグメントの範囲を見つけようとしました。
~からhttps://manybutfinite.com/post/anatomy-of-a-program-in-memory/、プロセスのメモリレイアウト図が見つかりました。
メモリマップされたセグメントとヒープが出会うまで増加し続けますか?
それとも、スタックセグメントのRLIMIT_STACKと同様に、2つのセグメントの成長に制限がありますか?
Linuxプログラミングインターフェースから
ヒープとスタックを増やすためのスペースを許可するために、共有メモリセグメントは仮想アドレス0x40000000から始まり接続されます。マッピングマッピング(49章)と共有ライブラリ(41章と42章)もこの領域に配置されます。 (カーネルのバージョンとプロセスの RLIMIT_STACK リソース制限の設定によっては、共有メモリマップとメモリセグメントのデフォルトの配置に若干の違いがあります。) アドレス 0x40000000 は、カーネル定数 TASK_UNMAPPED_BASE として定義されます。
共有メモリセグメントはTASK_UNMAPPED_BASEから始まり、上向きに増加しますか?
上の図は、共有メモリセグメントが下向きに増加することを示しているので、上向きに成長するのか、それとも下向きに成長するのですか?
ありがとうございます。
ベストアンサー1
mmap
セグメントとヒープセグメントにはいくつかの制限が適用されます。RLIMIT_AS
使用可能な総アドレス空間を決定します。これには、プログラムが作成できるすべてのメモリ割り当てが含まれます。RLIMIT_DATA
データセグメントの最大サイズを決定します。
カーネルはこれらの制限についてスタック拡張とmmap
ヒープbrk
割り当てをチェックします。また、競合の可能性があるセグメントへの割り当てを確認するため、セグメントが互いに上書きされないようになります(たとえば、参照)。ヒープ割り当てに対して実行される検査brk
)。割り当てができない場合は、プログラムに適切に「通知されます」。 Cライブラリはエラーを返し、ENOMEM
スタックを拡張できない場合、brk
カーネルは次のようにプログラムを終了します。SIGSEGV
共有メモリセグメント(厳密に言えば、カーネルの観点から仮想メモリ領域)が大きくなる方法は、メモリレイアウトによって異なります。これはプロセスごとに大きく異なる可能性があります。ほとんどのアーキテクチャでは、「伝統的な」メモリマッピングがありますTASK_UNMAPPED_BASE
。非伝統的なメモリマッピングはトップダウン割り当てをもたらす。バラよりarch_pick_mmap_layout()
そしてmmap_is_legacy()
x86アーキテクチャを例にしてみましょう。setarch
'フラグを使用して古いメモリマップに切り替えることができます-L
(下記の例を参照)。
実際に/proc/$$/maps
ロードされた共有ライブラリのアドレス(存在する場合)とロードされた順序を表示して調べて、セグメントがどのように増加するかを理解できます。動的リンカーは常に最初にロードされます。そのアドレスが他のライブラリよりも低い場合、割り当てはボトムアップ、それ以外の場合はトップダウンです。 64ビットx86システムの出力を比較しますcat /proc/self/maps
。setarch x86_64 -L cat /proc/self/maps