Lingkungan POSIX menyediakan setidaknya dua cara untuk mengakses file. Ada panggilan sistem standar open()
, read()
, write()
, dan teman-teman, tapi ada juga pilihan untuk menggunakan mmap()
untuk memetakan file ke memori virtual.
Kapan lebih baik menggunakan yang satu dari yang lainnya? Apa keunggulan masing-masing yang pantas termasuk dua antarmuka?
Jawaban:
mmap
sangat bagus jika Anda memiliki beberapa proses mengakses data dengan cara hanya baca dari file yang sama, yang umum dalam jenis sistem server yang saya tulis.mmap
memungkinkan semua proses untuk berbagi halaman memori fisik yang sama, menghemat banyak memori.mmap
juga memungkinkan sistem operasi untuk mengoptimalkan operasi paging. Misalnya, pertimbangkan dua program; programA
yang membaca1MB
file menjadi buffermalloc
, dan program B yangmmaps
file 1MB menjadi memori. Jika sistem operasi harus menukar sebagianA
memori keluar, ia harus menulis konten buffer untuk menukar sebelum dapat menggunakan kembali memori. DalamB
hal apapunmmap
halaman yang tidak dimodifikasi dapat digunakan kembali dengan segera karena OS tahu cara mengembalikannya dari file yang sudah adammap
. (OS dapat mendeteksi halaman mana yang tidak dimodifikasi dengan awalnya menandaimmap
halaman yang dapat ditulis sebagai hanya baca dan menangkap kesalahan seg , mirip dengan strategi Copy on Write ).mmap
juga berguna untuk komunikasi antar proses . Anda bisammap
file sebagai baca / tulis dalam proses yang perlu berkomunikasi dan kemudian menggunakan primitif sinkronisasi dimmap'd
wilayah (ini adalah apaMAP_HASSEMAPHORE
bendera untuk).Satu tempat yang
mmap
bisa menjadi canggung adalah jika Anda perlu bekerja dengan file yang sangat besar pada mesin 32 bit. Ini karenammap
harus menemukan blok alamat yang berdekatan di ruang alamat proses Anda yang cukup besar untuk memenuhi seluruh rentang file yang dipetakan. Ini bisa menjadi masalah jika ruang alamat Anda menjadi terfragmentasi, di mana Anda mungkin memiliki ruang alamat 2 GB gratis, tetapi tidak ada rentang individu yang dapat memuat pemetaan file 1 GB. Dalam hal ini Anda mungkin harus memetakan file dalam potongan yang lebih kecil daripada yang Anda inginkan agar sesuai.Kecanggihan potensial lain dengan
mmap
sebagai pengganti baca / tulis adalah bahwa Anda harus memulai pemetaan Anda pada offset ukuran halaman. Jika Anda hanya ingin mendapatkan beberapa data pada offset,X
Anda harus memperbaiki offset itu sehingga kompatibel dengannyammap
.Dan akhirnya, baca / tulis adalah satu-satunya cara Anda dapat bekerja dengan beberapa jenis file.
mmap
tidak dapat digunakan pada hal-hal seperti pipa dan ttys .sumber
MAP_HASSEMAPHORE
khusus untuk BSD.Satu area di mana saya menemukan mmap () tidak menjadi keuntungan adalah ketika membaca file kecil (di bawah 16K). Overhead halaman salah untuk membaca seluruh file sangat tinggi dibandingkan dengan hanya melakukan panggilan sistem read () tunggal. Ini karena kernel kadang-kadang dapat membuat read sepenuhnya dalam slice waktu Anda, yang berarti kode Anda tidak beralih. Dengan kesalahan halaman, sepertinya lebih mungkin bahwa program lain akan dijadwalkan, membuat operasi file memiliki latensi yang lebih tinggi.
sumber
malloc
sepotong memori dan membuat 1read
ke dalamnya. Ini memungkinkan untuk memiliki kode yang sama yang menangani peta memori menangani malloc'ed.read
akses lebih tinggi daripada overhead manipulasi memori virtual.mmap
harus memperbarui 4 entri dalam tabel halaman. Tetapi menggunakanread
untuk menyalin ke buffer 16K juga melibatkan memperbarui entri tabel 4 halaman, belum lagi perlu menyalin 16K ke dalam ruang addr pengguna. Jadi, bisakah Anda menguraikan perbedaan operasi pada tabel halaman, dan bagaimana harganya lebih mahalmmap
?mmap
memiliki keuntungan ketika Anda memiliki akses acak pada file besar. Keuntungan lain adalah Anda mengaksesnya dengan operasi memori (memcpy, pointer aritmatika), tanpa repot dengan buffering. I / O yang normal kadang-kadang bisa sangat sulit ketika menggunakan buffer ketika Anda memiliki struktur yang lebih besar dari buffer Anda. Kode untuk menangani yang seringkali sulit untuk diperbaiki, mmap umumnya lebih mudah. Ini mengatakan, ada jebakan tertentu ketika bekerja denganmmap
. Seperti yang telah disebutkan orang,mmap
pengaturannya cukup mahal, sehingga layak digunakan hanya untuk ukuran tertentu (bervariasi dari mesin ke mesin).Untuk akses berurutan murni ke file, itu juga tidak selalu merupakan solusi yang lebih baik, meskipun panggilan yang tepat untuk
madvise
dapat mengurangi masalah.Anda harus berhati-hati dengan pembatasan perataan arsitektur Anda (SPARC, itanium), dengan baca / tulis IO buffer sering disejajarkan dengan benar dan tidak menjebak ketika mendereferensi pointer yang dicor.
Anda juga harus berhati-hati agar tidak mengakses di luar peta. Itu dapat dengan mudah terjadi jika Anda menggunakan fungsi string pada peta Anda, dan file Anda tidak mengandung \ 0 di bagian akhir. Ini akan berfungsi sebagian besar waktu ketika ukuran file Anda bukan kelipatan dari ukuran halaman karena halaman terakhir diisi dengan 0 (area yang dipetakan selalu dalam ukuran kelipatan dari ukuran halaman Anda).
sumber
Selain jawaban bagus lainnya, kutipan dari pemrograman sistem Linux ditulis oleh pakar Google Robert Love:
sumber
Pemetaan memori memiliki potensi untuk keunggulan kecepatan yang sangat besar dibandingkan dengan IO tradisional. Ini memungkinkan sistem operasi membaca data dari file sumber saat halaman dalam file yang dipetakan memori disentuh. Ini berfungsi dengan membuat halaman yang salah, yang dideteksi OS dan kemudian OS memuat data terkait dari file secara otomatis.
Ini bekerja dengan cara yang sama seperti mekanisme paging dan biasanya dioptimalkan untuk I / O kecepatan tinggi dengan membaca data pada batas dan ukuran halaman sistem (biasanya 4K) - ukuran yang dioptimalkan untuk kebanyakan cache sistem file.
sumber
pread
. Pada Solaris 9 Sparc (V890) akses pread berada di antara 2 dan 3 kali lebih lambatmemcpy
dari pada mmap. Tapi Anda benar bahwa akses berurutan tidak perlu lebih cepat.Keuntungan yang belum terdaftar adalah kemampuan
mmap()
untuk menjaga pemetaan hanya baca sebagai halaman bersih . Jika seseorang mengalokasikan buffer di ruang alamat proses, kemudian digunakanread()
untuk mengisi buffer dari file, halaman memori yang sesuai dengan buffer itu sekarang kotor karena telah ditulis.Halaman kotor tidak dapat dijatuhkan dari RAM oleh kernel. Jika ada ruang swap, maka mereka bisa keluar untuk bertukar. Tapi ini mahal dan pada beberapa sistem, seperti perangkat tertanam kecil dengan hanya memori flash, tidak ada swap sama sekali. Dalam hal ini, buffer akan terjebak dalam RAM sampai proses keluar, atau mungkin mengembalikannya
madvise()
.Non ditulis ke
mmap()
halaman bersih. Jika kernel membutuhkan RAM, ia dapat dengan mudah menjatuhkannya dan menggunakan RAM tempat halaman berada. Jika proses yang memetakan mengaksesnya lagi, itu menyebabkan kesalahan halaman kernel memuat kembali halaman-halaman dari file asalnya. . Cara yang sama mereka dihuni di tempat pertama.Ini tidak memerlukan lebih dari satu proses menggunakan file yang dipetakan untuk menjadi keuntungan.
sumber
read()
, halaman-halaman yang datanya dimasukkan tidak memiliki hubungan dengan file asal mereka. Jadi mereka tidak bisa dituliskan, kecuali untuk menukar ruang. Jika suatu filemmap()ed
, dan pemetaan dapat ditulis (bukan hanya baca), dan ditulis ke, maka itu tergantung pada apakah pemetaan ituMAP_SHARED
atau tidakMAP_PRIVATE
. Pemetaan bersama bisa / harus ditulis ke file, tetapi pribadi tidak bisa.