Memuat perpustakaan bersama dan penggunaan RAM

41

Saya bertanya-tanya tentang cara Linux mengelola perpustakaan bersama. (sebenarnya saya sedang berbicara tentang Maemo Fremantle, distro berbasis Debian dirilis pada tahun 2009 berjalan pada RAM 256MB).

Mari kita asumsikan kita memiliki dua executable yang terhubung ke libQtCore.so.4 dan menggunakan simbol-simbolnya (menggunakan kelas dan fungsinya). Demi kesederhanaan, mari kita memanggil mereka adan b. Kami berasumsi bahwa kedua executable terhubung ke perpustakaan yang sama.

Pertama kita luncurkan a. Perpustakaan harus dimuat. Apakah ini dimuat secara keseluruhan atau hanya dimuat ke memori di bagian yang diperlukan (karena kami tidak menggunakan setiap kelas, hanya kode mengenai kelas yang digunakan sedang dimuat)?

Lalu kami meluncurkan b. Kami menganggap itu amasih berjalan. btautan ke libQtCore.so.4 juga dan menggunakan beberapa kelas yang amenggunakan, tetapi juga beberapa yang tidak digunakan oleh a. Apakah perpustakaan akan dimuat ganda (secara terpisah untuk adan secara terpisah untuk b)? Atau apakah mereka akan menggunakan objek yang sama dalam RAM. Jika btidak menggunakan simbol baru dan asudah berjalan, apakah RAM yang digunakan oleh perpustakaan bersama akan meningkat? (Atau perbedaannya tidak signifikan)

marmistrz
sumber

Jawaban:

54

CATATAN: Saya akan menganggap bahwa mesin Anda memiliki unit pemetaan memori (MMU). Ada versi Linux (μClinux) yang tidak memerlukan MMU, dan jawaban ini tidak berlaku di sana.

Apa itu MMU? Ini adalah perangkat keras — bagian dari prosesor dan / atau pengontrol memori. Memahami penautan pustaka bersama tidak mengharuskan Anda untuk memahami cara kerja MMU, hanya MMU yang memungkinkan ada perbedaan antara alamat memori logis (yang digunakan oleh program) dan fisikalamat memori (yang sebenarnya ada di bus memori). Memori dipecah menjadi beberapa halaman, biasanya berukuran 4K di Linux. Dengan halaman 4k, alamat logis 0–4095 adalah halaman 0, alamat logis 4096–8191 adalah halaman 1, dll. MMU memetakannya ke halaman fisik RAM, dan setiap halaman logis biasanya dapat dipetakan ke 0 atau 1 halaman fisik. Halaman fisik yang diberikan dapat sesuai dengan beberapa halaman logis (ini adalah bagaimana memori dibagi: beberapa halaman logis sesuai dengan halaman fisik yang sama). Catatan ini berlaku terlepas dari OS; ini adalah deskripsi perangkat keras.

Pada sakelar proses, kernel mengubah pemetaan halaman MMU, sehingga setiap proses memiliki ruangnya sendiri. Alamat 4096 dalam proses 1000 dapat (dan biasanya) sama sekali berbeda dari alamat 4096 dalam proses 1001.

Cukup banyak setiap kali Anda melihat alamat, itu adalah alamat yang logis. Program ruang pengguna jarang berurusan dengan alamat fisik.

Sekarang, ada banyak cara untuk membangun perpustakaan juga. Katakanlah program memanggil fungsi foo()di perpustakaan. CPU tidak tahu apa-apa tentang simbol, atau fungsi benar-benar memanggil — ia hanya tahu cara melompat ke alamat logis, dan mengeksekusi kode apa pun yang ditemukan di sana. Ada beberapa cara untuk melakukan ini (dan hal-hal serupa berlaku ketika perpustakaan mengakses data globalnya sendiri, dll.):

  1. Ini bisa membuat kode-keras beberapa alamat logis untuk memanggilnya di. Ini mengharuskan perpustakaan selalu dimuat pada alamat logis yang sama persis. Jika dua perpustakaan memerlukan alamat yang sama, penautan dinamis gagal dan Anda tidak dapat meluncurkan program. Perpustakaan dapat memerlukan perpustakaan lain, jadi ini pada dasarnya mengharuskan setiap perpustakaan pada sistem untuk memiliki alamat logis yang unik. Ini sangat cepat, jika berhasil. (Ini adalah bagaimana a.out melakukan sesuatu, dan jenis pengaturan yang dilakukan prelinking, semacam).
  2. Ini bisa membuat kode-keras alamat logis palsu, dan memberi tahu tautan dinamis untuk mengedit di alamat yang benar ketika memuat perpustakaan. Ini menghabiskan sedikit waktu ketika memuat perpustakaan, tetapi setelah itu sangat cepat.
  3. Itu bisa menambahkan lapisan tipuan: gunakan register CPU untuk menyimpan alamat logis tempat perpustakaan dimuat, dan kemudian mengakses semuanya sebagai offset dari register itu. Ini membebankan biaya kinerja pada setiap akses.

Cukup banyak yang tidak menggunakan # 1 lagi, setidaknya tidak pada sistem tujuan umum. Mempertahankan daftar alamat logis unik tidak mungkin pada sistem 32-bit (tidak ada cukup untuk berkeliling) dan mimpi buruk administratif pada sistem 64-bit. Pre-linking melakukan hal ini, pada basis per-sistem.

Apakah # 2 atau # 3 digunakan tergantung pada apakah perpustakaan dibangun dengan -fPICopsi (kode bebas posisi) GCC . # 2 tanpa, # 3 dengan. Secara umum, perpustakaan dibangun dengan -fPIC, jadi # 3 adalah apa yang terjadi.

Untuk detail lebih lanjut, lihat Bagaimana Menulis Perpustakaan Bersama Ulrich Drepper (PDF) .

Jadi, akhirnya, pertanyaan Anda dapat dijawab:

  1. Jika perpustakaan dibangun dengan -fPIC (seperti yang seharusnya), sebagian besar halaman persis sama untuk setiap proses yang memuatnya. Proses Anda adan bmungkin memuat pustaka di berbagai alamat logis, tetapi itu akan mengarah ke halaman fisik yang sama: memori akan dibagikan. Selanjutnya, data dalam RAM sama persis dengan apa yang ada di disk, sehingga hanya dapat dimuat saat dibutuhkan oleh penangan kesalahan halaman.
  2. Jika perpustakaan dibangun tanpa -fPIC , maka sebagian besar halaman perpustakaan akan membutuhkan suntingan tautan, dan akan berbeda. Oleh karena itu, mereka harus terpisah halaman fisik (karena mengandung data yang berbeda). Itu berarti mereka tidak dibagikan. Halaman-halaman tidak cocok dengan apa yang ada di disk, jadi saya tidak akan terkejut jika seluruh perpustakaan dimuat. Tentu saja kemudian dapat ditukar ke disk (di swapfile).

Anda dapat memeriksa ini dengan pmapalat ini, atau langsung dengan memeriksa berbagai file di /proc. Sebagai contoh, berikut adalah output (parsial) dari pmap -xdua s yang berbeda yang baru saja dihasilkan bc. Perhatikan bahwa alamat yang ditunjukkan oleh pmap adalah, sebagai alamat biasa, logis:

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

Anda dapat melihat bahwa perpustakaan dimuat dalam beberapa bagian, dan pmap -xmemberi Anda detail pada masing-masing bagian secara terpisah. Anda akan melihat bahwa alamat logis berbeda antara kedua proses; Anda cukup berharap mereka menjadi sama (karena program yang sama berjalan, dan komputer biasanya dapat diprediksi seperti itu), tetapi ada fitur keamanan yang disebut pengacakan tata letak ruang alamat yang sengaja mengacak mereka.

Anda dapat melihat dari perbedaan ukuran (Kbytes) dan ukuran penduduk (RSS) bahwa seluruh segmen perpustakaan belum dimuat. Akhirnya, Anda dapat melihat bahwa untuk pemetaan yang lebih besar, kotor adalah 0, artinya sesuai dengan apa yang ada di disk.

Anda dapat menjalankannya kembali pmap -XX, dan ia akan menunjukkan kepada Anda — tergantung pada versi kernel yang Anda jalankan, karena -XX bervariasi berdasarkan versi kernel — yang pemetaan pertama memiliki Shared_Clean176, yang persis sama dengan RSS. Sharedmemori berarti halaman fisik dibagi antara beberapa proses, dan karena cocok dengan RSS, itu berarti semua perpustakaan yang ada dalam memori dibagi (lihat Lihat Juga di bawah untuk penjelasan lebih lanjut tentang dibagikan vs pribadi):

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


Lihat juga

derobert
sumber
Itu berarti prelink tidak ada gunanya lagi (dan -fPICpenggunaannya telah benar-benar berubah beberapa waktu yang lalu)?
Hauke ​​Laging
@ Chrisron Terima kasih atas koreksi. FYI, Penurunan harga akan dihitung untuk Anda — hasil yang diulang dari pengulangan saya 1. benar. Juga, saya membuat beberapa perubahan pada apa yang Anda lakukan— "alamat mulai" adalah jargon teknis, saya mungkin menyebabkan kebingungan dengan meletakkan "logis" di tengah. Saya mengubahnya untuk menyingkirkan jargon. Juga, halaman setara dengan alamat-alamat itu, AFAIK itu tidak mungkin bagi alamat-alamat itu untuk menjadi halaman yang berbeda. Saya mencoba lagi, menukar pesanan, mudah-mudahan itu lebih jelas.
derobert
sial, sekarang itu jawabannya !!!
Evan Carroll