共有ライブラリのロードとRAM使用量


40

Linuxが共有ライブラリを管理する方法について疑問に思っています。(実際、2009年にリリースされたDebianベースのディストリビューションである256MB RAMで実行されるMaemo Fremantleについて話しています)。

libQtCore.so.4にリンクし、そのシンボルを使用する(クラスと関数を使用する)2つの実行可能ファイルがあるとします。簡単にするために、それらをaおよびと呼びましょうb。両方の実行可能ファイルが同じライブラリにリンクすると仮定します。

最初に起動しaます。ライブラリをロードする必要があります。それは全体でロードされていますか、それとも必要な部分のみメモリにロードされていますか(各クラスを使用しないため、使用されたクラスに関するコードのみがロードされています)

その後、起動しbます。aまだ実行されていると仮定します。blibQtCore.so.4にもリンクし、使用するクラスのa一部を使用しaますが、で使用されないクラスも使用します。ライブラリは、二重(別途ロードされますaと別途b)?または、すでにRAMにある同じオブジェクトを使用します。場合bの使用は新たなシンボルとaすでに実行されているRAMは、共有ライブラリの増加によって使用されていないのだろうか?(または、違いはわずかです)

回答:


53

注:お使いのマシンにメモリマッピングユニット(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は、シンボルや関数呼び出しについては何も知りません。論理アドレスにジャンプし、そこで見つかったコードを実行する方法を知っているだけです。これを行うには、いくつかの方法があります(ライブラリが独自のグローバルデータにアクセスする場合など、同様のことが当てはまります)。

  1. 呼び出す論理アドレスをハードコーディングできます。これには、ライブラリが常にまったく同じ論理アドレスでロードされる必要があります。2つのライブラリが同じアドレスを必要とする場合、動的リンクは失敗し、プログラムを起動できません。ライブラリには他のライブラリが必要な場合があるため、基本的にはシステム上のすべてのライブラリに一意の論理アドレスが必要です。ただし、動作する場合は非常に高速です。(これはa.outがどのようにしたかであり、事前リンクが行うセットアップの種類です)。
  2. 偽の論理アドレスをハードコーディングし、ライブラリをロードするときに適切なアドレスで編集するように動的リンカーに指示できます。これには、ライブラリのロードにかなりの時間がかかりますが、その後は非常に高速です。
  3. インダイレクションのレイヤーを追加できます:ライブラリがロードされる論理アドレスを保持するためにCPUレジスタを使用し、そのレジスタからのオフセットとしてすべてにアクセスします。これにより、各アクセスにパフォーマンスコストがかかります。

少なくとも汎用システムでは、#1を使用する人はほとんどいません。32ビットシステムでは一意の論理アドレスリストを維持することは不可能であり(回避するには十分ではありません)、64ビットシステムでは管理上の悪夢です。ただし、事前リンクの並べ替えは、システムごとにこれを行います。

#2を使用するか#3を使用するかは、ライブラリがGCC -fPIC(位置独立コード)オプションでビルドされたかどうかによって異なります。#2はなし、#3はあり。一般に、ライブラリはで構築される-fPICため、#3が行われます。

詳細については、Ulrich Drepperの共有ライブラリの記述方法(PDF)を参照してください。

だから、最後に、あなたの質問に答えることができます:

  1. ライブラリが(ほぼ確実にそうであるように)ビルドされている 場合、-fPICページの大部分は、ロードするすべてのプロセスでまったく同じです。あなたのプロセスab同様に異なる論理アドレスでライブラリをロードする可能性がありますが、これらは同じ物理ページを指すようになります:メモリが共有されます。さらに、RAMのデータはディスク上のデータと正確に一致するため、ページフォールトハンドラーが必要とする場合にのみロードできます。
  2. ライブラリがなし -fPICで構築されている場合、ライブラリのほとんどのページでリンクの編集が必要になり、異なることがわかります。したがって、それらは別々の物理ページでなければなりません(異なるデータが含まれているため)。つまり、共有されていません。ページはディスク上にあるものと一致しないため、ライブラリ全体がロードされても驚かないでしょう。もちろん、その後(スワップファイルで)ディスクにスワップアウトできます。

これは、pmapツールを使用して、またはでさまざまなファイルをチェックして直接調べることができます/proc。たとえば、これはpmap -x2つの異なる新しく生成されたの(部分的な)出力ですbc。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_Clean176があり、これはに完全に一致していRSSます。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


こちらもご覧ください


これは、事前リンクはもう役に立たないことを意味します(そして、-fPIC使用法は少し前に完全に変更されました)?
ハウケレイジング14

@crisron修正をありがとう。参考までに、Markdownはあなたのためにカウントされます-私の繰り返しのレンダリングされた出力1. は正しかったです。また、私はあなたがしたことに対していくつかの変更を加えました。「開始アドレス」は技術的な専門用語です。専門用語を取り除くために変更しました。また、ページはそれらのアドレスに相当しますが、それらのアドレスが異なるページになることは不可能です。順番を入れ替えて、もう一度試してみましたが、うまくいけばもっとわかりやすくなります。
デロバート14

いまいましい、それが答えだ!!!
エヴァンキャロル
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.