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.):
- 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).
- 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.
- 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 -fPIC
opsi (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:
- Jika perpustakaan dibangun dengan
-fPIC
(seperti yang seharusnya), sebagian besar halaman persis sama untuk setiap proses yang memuatnya. Proses Anda a
dan b
mungkin 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.
- 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 pmap
alat ini, atau langsung dengan memeriksa berbagai file di /proc
. Sebagai contoh, berikut adalah output (parsial) dari pmap -x
dua 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 -x
memberi 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_Clean
176, yang persis sama dengan RSS
. Shared
memori 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
-fPIC
penggunaannya telah benar-benar berubah beberapa waktu yang lalu)?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.