Linuxが共有ライブラリを管理する方法について疑問に思っています。 (実際には、2009年にリリースされた256MBのRAMで動作するDebianベースのディストリビューションであるMaemo Fremantleについて話しています。)
libQtCore.so.4にリンクし、そのシンボルを使用する(クラスと関数を使用する)2つの実行可能ファイルがあると仮定します。簡単にするために、それらをa
と呼びましょう。 およびb
。両方の実行可能ファイルが同じライブラリにリンクしていることを前提としています。
まず、a
を起動します 。ライブラリをロードする必要があります。全体が読み込まれるのですか、それとも必要な部分だけがメモリに読み込まれるのですか(各クラスを使用しないため、使用されるクラスに関するコードのみが読み込まれます)。
次に、b
を起動します 。 a
まだ実行中です。 b
libQtCore.so.4にもリンクし、a
のクラスの一部を使用します を使用しますが、a
によって使用されないものもあります 。ライブラリはダブルロードされますか(a
とは別に) b
とは別に )?または、すでにRAMにある同じオブジェクトを使用しますか。 b
の場合 新しい記号を使用せず、a
すでに実行されています共有ライブラリで使用されるRAMは増加しますか? (または、違いは重要ではありません)
承認された回答:
注:お使いのマシンにはメモリマッピングユニット(MMU)があると想定します。 MMUを必要としないLinuxバージョン(µClinux)があり、この回答はそこには当てはまりません。
MMUとは何ですか?それはハードウェアであり、プロセッサやメモリコントローラの一部です。共有ライブラリのリンクを理解するために、MMUがどのように機能するかを正確に理解する必要はありません。ただ、MMUによって論理の間に違いが生じる可能性があります。 メモリアドレス(プログラムで使用されるアドレス)と物理 メモリアドレス(メモリバスに実際に存在するアドレス)。メモリはページに分割されます。Linuxでは通常4Kのサイズです。 4kページの場合、論理アドレス0〜4095はページ0、論理アドレス4096〜8191はページ1などです。MMUはそれらをRAMの物理ページにマップし、各論理ページは通常0または1の物理ページにマップできます。特定の物理ページは複数の論理ページに対応できます(これがメモリの共有方法です。複数の論理ページは同じ物理ページに対応します)。これはOSに関係なく適用されることに注意してください。ハードウェアの説明です。
プロセスの切り替え時に、カーネルはMMUページのマッピングを変更して、各プロセスが独自のスペースを持つようにします。プロセス1000のアドレス4096は、プロセス1001のアドレス4096とは完全に異なる場合があります(通常は異なります)。
ほとんどの場合、アドレスが表示されると、それは論理アドレスです。ユーザースペースプログラムが物理アドレスを処理することはほとんどありません。
現在、ライブラリを構築する方法も複数あります。プログラムが関数foo()
を呼び出すとしましょう 図書館で。 CPUは、シンボルや関数呼び出しについては何も知りません。論理アドレスにジャンプして、そこで見つかったコードを実行する方法を知っているだけです。これを行うにはいくつかの方法があります(ライブラリが独自のグローバルデータにアクセスする場合などにも同様のことが当てはまります):
- 呼び出す論理アドレスをハードコーディングすることができます。これには、ライブラリが常に必要です。 まったく同じ論理アドレスにロードされます。 2つのライブラリが同じアドレスを必要とする場合、ダイナミックリンクは失敗し、プログラムを起動できません。ライブラリは他のライブラリを必要とする可能性があるため、これには基本的に、システム上のすべてのライブラリが一意の論理アドレスを持っている必要があります。ただし、機能する場合は非常に高速です。 (これは、a.outが物事を行った方法であり、事前リンクが行うような設定です。)
- 偽の論理アドレスをハードコーディングし、ライブラリをロードするときに適切なアドレスで編集するようにダイナミックリンカに指示する可能性があります。これには、ライブラリをロードするときにかなりの時間がかかりますが、その後は非常に高速です。
- 間接層を追加する可能性があります。CPUレジスタを使用してライブラリがロードされる論理アドレスを保持し、そのレジスタからのオフセットとしてすべてにアクセスします。これにより、各アクセスにパフォーマンスコストがかかります。
少なくとも汎用システムでは、ほとんど誰も#1を使用していません。その一意の論理アドレスリストを保持することは、32ビットシステムでは不可能であり(回避するのに十分ではありません)、64ビットシステムでは管理上の悪夢です。ただし、事前リンクの種類は、システムごとにこれを行います。
#2と#3のどちらを使用するかは、ライブラリがGCCの-fPIC
で構築されているかどうかによって異なります。 (位置独立コード)オプション。 #2はなし、#3はあり。通常、ライブラリは-fPIC
で構築されます 、つまり#3が発生します。
詳細については、Ulrich Drepperの共有ライブラリの作成方法(PDF)を参照してください。
それで、最後に、あなたの質問に答えることができます:
- ライブラリがで構築されている場合
-fPIC
(ほぼ確実にそうあるべきですが)、ページの大部分は、それをロードするすべてのプロセスでまったく同じです。プロセスa
およびb
ライブラリを異なる論理アドレスにロードすることもできますが、それらは同じ物理ページを指します。メモリは共有されます。さらに、RAM内のデータはディスク上のデータと完全に一致するため、ページフォールトハンドラーが必要とする場合にのみロードできます。 - ライブラリがなしで構築されている場合
-fPIC
、その後、ライブラリのほとんどのページでリンクの編集が必要になり、異なることがわかります。したがって、それらは別々の物理ページである必要があります(異なるデータが含まれているため)。つまり、それらは共有されません。ページがディスク上のページと一致しないため、ライブラリ全体が読み込まれていても驚かないでしょう。もちろん、後でディスクに(スワップファイルで)スワップアウトすることもできます。
これはpmap
で調べることができます ツール、または/proc
内のさまざまなファイルを直接チェックする 。たとえば、これはpmap -x
の(部分的な)出力です。 2つの異なる新しく生成されたbc
s。 pmapで示されるアドレスは、通常、論理アドレスであることに注意してください。
pmap -x 14739
Address Kbytes RSS Dirty Mode Mapping
00007f81803ac000 244 176 0 r-x-- libreadline.so.6.2
00007f81803e9000 2048 0 0 ----- libreadline.so.6.2
00007f81805e9000 8 8 8 r---- libreadline.so.6.2
00007f81805eb000 24 24 24 rw--- libreadline.so.6.2
pmap -x 17739
Address Kbytes RSS Dirty Mode Mapping
00007f784dc77000 244 176 0 r-x-- libreadline.so.6.2
00007f784dcb4000 2048 0 0 ----- libreadline.so.6.2
00007f784deb4000 8 8 8 r---- libreadline.so.6.2
00007f784deb6000 24 24 24 rw--- libreadline.so.6.2
ライブラリが複数の部分にロードされていることがわかります。pmap -x
それぞれの詳細を個別に提供します。 2つのプロセス間で論理アドレスが異なることに気付くでしょう。それらは同じであると合理的に期待できますが(同じプログラムが実行されており、コンピューターは通常そのように予測可能であるため)、意図的にランダム化するアドレス空間配置のランダム化と呼ばれるセキュリティ機能があります。
サイズ(Kバイト)と常駐サイズ(RSS)の違いから、ライブラリセグメント全体がロードされていないことがわかります。最後に、より大きなマッピングの場合、dirtyは0であり、ディスク上にあるものに正確に対応していることがわかります。
pmap -XX
を使用して再実行できます 、そして、実行しているカーネルのバージョンに応じて、-XX出力はカーネルのバージョンによって異なるため、最初のマッピングにShared_Clean
があることが示されます。 RSS
と完全に一致する176の 。 Shared
メモリとは、物理ページが複数のプロセス間で共有されることを意味し、RSSと一致するため、メモリ内にあるすべてのライブラリが共有されることを意味します(共有とプライベートの詳細については、以下の「関連項目」を参照してください):
pmap -XX 17739
Address Perm Offset Device Inode Size Rss Pss Shared_Clean Shared_Dirty Private_Clean Private_Dirty Referenced Anonymous AnonHugePages Swap KernelPageSize MMUPageSize Locked VmFlagsMapping
7f784dc77000 r-xp 00000000 fd:00 1837043 244 176 19 176 0 0 0 176 0 0 0 4 4 0 rd ex mr mw me sd libreadline.so.6.2
7f784dcb4000 ---p 0003d000 fd:00 1837043 2048 0 0 0 0 0 0 0 0 0 0 4 4 0 mr mw me sd libreadline.so.6.2
7f784deb4000 r--p 0003d000 fd:00 1837043 8 8 8 0 0 0 8 8 8 0 0 4 4 0 rd mr mw me ac sd libreadline.so.6.2
7f784deb6000 rw-p 0003f000 fd:00 1837043 24 24 24 0 0 0 24 24 24 0 0 4 4 0 rd wr mr mw me ac sd libreadline.so.6.2
関連項目
- プロセスのメモリ使用量に関する情報を/proc/ pid / smapsから取得して、クリーン/ダーティ共有/プライベート全体の説明を取得します。