Dosya erişimi için ne zaman mmap kullanmalıyım?


276

POSIX ortamları dosyalara erişmenin en az iki yolunu sunar. Sistem çağrıları standart var open(), read(), write()ve arkadaşları, ancak kullanma seçeneği de var mmap()sanal belleğe dosyayı eşleştirmek için.

Birini diğerinin üzerinde kullanmak ne zaman tercih edilir? İki arayüz içeren liyakat avantajları nelerdir?


16
Ayrıca bkz. Mmap () vs. okuma blokları ve Linus Torvalds'ın bu yazısı buradaki cevaplardan birinde atıfta bulundu.
MvG

Yanıtlar:


299

mmapaynı dosyadan salt okunur bir şekilde verilere erişen birden çok işleminiz varsa, bu da yazdığım sunucu sistemleri türünde yaygın olan bir işlemdir. mmaptüm bu işlemlerin aynı fiziksel bellek sayfalarını paylaşmasını sağlayarak çok fazla bellek tasarrufu sağlar.

mmapayrıca işletim sisteminin disk belleği işlemlerini optimize etmesini sağlar. Örneğin, iki programı düşünün; Program A, bir okur 1MBile oluşturan bir tampon içine dosya mallocve programı B olan mmaps1 MB dosya belleğe. İşletim sisteminin Abelleğinin bir kısmını değiştirmek zorunda kalması durumunda, belleği yeniden kullanabilmesi için değiştirilecek arabellek içeriğini yazması gerekir. Bu Bdurumda, değiştirilmemiş tüm mmapsayfalar derhal yeniden kullanılabilir çünkü işletim sistemi, bulundukları dosyadan nasıl geri yükleneceğini bilir mmap. (İşletim sistemi, yazılabilir mmap'd sayfalarını başlangıçta salt okunur olarak işaretleyerek ve Yazarken Kopyala stratejisine benzer şekilde segment hatalarını yakalayarak hangi sayfaların değiştirilmediğini algılayabilir ).

mmapsüreçler arası iletişim için de yararlıdır . mmapBir dosyayı iletişim kurması gereken süreçlerde okuma / yazma olarak yapabilir ve daha sonra mmap'dbölgede senkronizasyon ilkellerini kullanabilirsiniz ( MAP_HASSEMAPHOREbayrağın amacı budur).

Bir yerde mmapgarip olabilir bir 32 bit makinede çok büyük dosyalarla çalışmak gerekiyorsa. Bunun nedeni mmap, işleminizin adres alanında eşlenen dosyanın tüm aralığına sığacak kadar büyük bir bitişik adres bloğu bulması gerektiğidir. Adres alanınız parçalanırsa, 2 GB'lık adres alanınız boş olabilir, ancak tek bir aralığı 1 GB dosya eşlemesine sığamazsa bu sorun olabilir. Bu durumda, dosyayı sığdırmak istediğinizden daha küçük parçalar halinde eşlemeniz gerekebilir.

mmapOkuma / yazma yerine başka bir olası gariplik , eşlemenizi sayfa boyutunun ofsetlerinde başlatmanız gerektiğidir. Sadece ofsette bazı veriler almak Xistiyorsanız, bu ofseti ile uyumlu olması için düzeltmeniz gerekecektir mmap.

Ve son olarak, okuma / yazma yalnızca yoldur okumak yapabilirsiniz dosyaları bazı türleri ile çalışır. boru ve ttymmap gibi şeylerde kullanılamaz .


10
Büyüyen dosyalarda mmap () kullanabilir misiniz? Veya mmap () belleği / dosyasını ayırdığınızda boyut sabit mi?
Jonathan Leffler

29
Mmap araması yaparken bir boyut belirtmeniz gerekir. Yani kuyruk işlemi gibi bir şey yapmak istiyorsanız çok uygun değil.
Don Neufeld

5
Afaik BSD'ye MAP_HASSEMAPHOREözgüdür.
Patrick Schlüter

6
@JonathanLeffler Kesinlikle büyüyen dosyalarda mmap () kullanabilirsiniz, ancak dosya başlangıçta ayırdığınız alan sınırına ulaştığında mmap () öğesini yeni boyutla yeniden çağırmanız gerekir. LevelDB'den PosixMmapFile size iyi bir örnek verir. Ama 1.15'ten mmap kullanmayı bıraktı. Sen eski bir sürümünü alabilirsiniz Github
baotiao

4
mmap, bir dosyanın birden fazla geçişte işlenmesi gerektiğinde de yararlı olabilir: sanal bellek sayfalarını tahsis etme maliyeti yalnızca bir kez ödenir.
Pergel

69

Mmap () 'nin bir avantaj olmadığını bulduğum bir alan, küçük dosyaları (16K'nın altında) okurken oldu. Tüm dosyayı okuyamayan sayfanın ek yükü, yalnızca tek bir read () sistem çağrısı yapmakla karşılaştırıldığında çok yüksekti. Bunun nedeni, çekirdeğin bazen zaman diliminizdeki bir okumayı tamamen tatmin edebilmesidir, yani kodunuz değişmez. Bir sayfa hatası olduğunda, dosya işleminin daha yüksek bir gecikme süresine neden olarak başka bir programın zamanlanmış olması daha olası görünüyordu.


4
+1 Bunu onaylayabilirim. Küçük dosyalar için mallocbir bellek parçası daha hızlıdır ve readiçine 1 yapmak daha hızlıdır . Bu, bellek haritalarını işleyen aynı koda sahip olmamaya izin verir.
Patrick Schlüter

35
Bu, bunun gerekçesinin doğru olmadığını söyledi. Zamanlayıcının farkla hiçbir ilgisi yoktur. Aradaki fark, hangi işlemlerin hangi bellek sayfasını ve erişim haklarını elinde tuttuğunu gösteren çekirdeğin küresel bir yapısı olan sayfa tablolarına yazma erişiminden gelir. Bu işlem çok maliyetli olabilir (önbellek hatlarını geçersiz kılabilir, TLB'den geçebilir, tablo küreseldir, bu nedenle eşzamanlı erişime karşı korunmalıdır vb.). readErişim yükünün sanal bellek manipülasyonunun yükünden daha yüksek olması için belirli bir harita boyutuna ihtiyacınız vardır .
Patrick Schlüter

1
@ PatrickSchlüter Tamam, mmap () başlangıcında sayfa tablosunun değiştirilmesini içeren bir ek yük olduğunu anlıyorum. Diyelim ki bir dosyanın 16K'sını belleğe eşleştiriyoruz. 4K sayfa boyutu mmapiçin, sayfa tablosundaki 4 girişi güncellemek zorundadır. Ancak read16K'lık bir ara belleğe kopyalamak için kullanılması, 16K'nın kullanıcı addr alanına kopyalanması gerektiğinden bahsetmemek için 4 sayfa tablosu girişlerini güncellemeyi de içerir. Öyleyse sayfa tablosundaki işlemlerin farklılıkları ve bunun için ne kadar pahalı olduğunu açıklayabilir mmapmisiniz?
flow2k

45

mmapbüyük dosyalara rastgele erişiminiz olduğunda avantaj sağlar. Başka bir avantajı, bellek işlemleriyle (memcpy, işaretçi aritmetiği), arabelleğe alma ile uğraşmadan erişmenizdir. Tamponunuzdan daha büyük yapılarınız olduğunda tamponlar kullanılırken normal G / Ç bazen oldukça zor olabilir. İşlenmesi gereken kod genellikle doğru bir şekilde zordur, mmap genellikle daha kolaydır. Bu, çalışırken bazı tuzaklar olduğunu söyledi mmap. İnsanların daha önce de belirttiği gibi, mmapkurulumu oldukça pahalıdır, bu nedenle sadece belirli bir boyut için (makineden makineye değişiklik göstererek) kullanmaya değer.

Dosyaya saf sıralı erişim için, aynı zamanda her zaman daha iyi bir çözüm değildir, ancak uygun bir çağrı madvisesorunu hafifletebilir.

Mimarinizin hizalama kısıtlamalarına (SPARC, itanium) dikkat etmelisiniz, okuma / yazma G / Ç ile arabellekler genellikle düzgün bir şekilde hizalanır ve döküm işaretçisini silerken tuzak oluşturmaz.

Ayrıca haritanın dışına erişmemenize de dikkat etmelisiniz. Haritanızda dize işlevleri kullanırsanız ve dosyanız sonunda \ 0 içermiyorsa kolayca olabilir. Çoğu zaman dosya boyutu, son sayfa 0 ile doldurulduğu için sayfa boyutunun katı olmadığında çalışır (eşlenen alan her zaman sayfa boyutunuzun katının boyutundadır).


30

Diğer güzel cevaplara ek olarak, Google uzmanı Robert Love tarafından yazılmış Linux sistem programlamasından bir alıntı :

Avantajları mmap( )

Dosyaları kullanarak mmap( )standart read( )ve write( )sistem çağrılarına göre bir çok avantajı vardır . Aralarında:

  • Bellek eşlemeli bir dosyadan okuma ve bu dosyaya yazma , verinin kullanıcı alanı arabelleğine kopyalanması ve buradan alınması gereken sistem çağrılarını read( )veya write( )sistem çağrılarını kullanırken ortaya çıkan gereksiz kopyayı önler .

  • Potansiyel sayfa hatalarının yanı sıra, bellek eşlemeli bir dosyadan okuma ve bu dosyaya yazma, sistem çağrısı veya bağlam anahtarı yükü oluşturmaz. Belleğe erişmek kadar basit.

  • Birden çok işlem aynı nesneyi belleğe eşlediğinde, veriler tüm işlemler arasında paylaşılır. Salt okunur ve paylaşılan yazılabilir eşlemeler bütünüyle paylaşılır; özel yazılabilir eşlemeler henüz henüz yazılmamış COW (yazma üzerine kopyalama) sayfalarına sahiptir.

  • Harita etrafında arama, önemsiz işaretçi manipülasyonlarını içerir. lseek( )Sistem çağrısına gerek yoktur .

Bu nedenlerle, mmap( )birçok uygulama için akıllı bir seçimdir.

Dezavantajları mmap( )

Kullanırken aklınızda bulundurmanız gereken birkaç nokta vardır mmap( ):

  • Bellek eşlemeleri her zaman tamsayı boyutunda bir sayfadır. Böylece, yedekleme dosyasının boyutu ile tamsayı sayıda sayfa arasındaki fark boş alan olarak "boşa harcanır". Küçük dosyalar için, eşleştirmenin önemli bir yüzdesi boşa gidebilir. Örneğin, 4 KB'lik sayfalarda 7 baytlık eşleme 4.089 bayt harcar.

  • Bellek eşlemeleri işlemin adres alanına sığmalıdır. 32 bit adres alanı ile, çok sayıda çeşitli boyutlu eşleme, adres alanının parçalanmasına neden olabilir ve bu da büyük serbest bitişik bölgeler bulmayı zorlaştırabilir. Bu sorun, elbette, 64 bit adres alanı ile çok daha az belirgindir.

  • Çekirdek içindeki bellek eşlemelerini ve ilişkili veri yapılarını oluşturma ve sürdürme yükü vardır. Bu ek yük genellikle, özellikle daha büyük ve sık erişilen dosyalar için, önceki bölümde belirtilen çift kopyanın ortadan kaldırılmasıyla ortadan kaldırılır.

Bu nedenlerden dolayı, mmap( )en büyük avantajı , eşlenen dosya büyük olduğunda (ve dolayısıyla boşa harcanan alan toplam eşlemenin küçük bir yüzdesi olduğunda) veya eşlenen dosyanın toplam boyutu sayfa boyutuna eşit olarak bölünebiliyorsa ( ve böylece boşa harcanan yer yoktur).


13

Bellek eşleme, geleneksel IO'ya kıyasla büyük bir hız avantajı potansiyeline sahiptir. Bellek eşlemeli dosyadaki sayfalara dokunulduğunda işletim sisteminin verileri kaynak dosyadan okumasını sağlar. Bu, işletim sisteminin tespit ettiği ve daha sonra işletim sisteminin ilgili verileri dosyadan otomatik olarak yüklediği hata sayfaları oluşturarak çalışır.

Bu, disk belleği mekanizmasıyla aynı şekilde çalışır ve genellikle sistem sayfası sınırları ve boyutlarındaki (genellikle 4K) verileri okuyarak yüksek hızlı G / Ç için optimize edilir - çoğu dosya sistemi önbelleğinin en iyi duruma getirildiği bir boyuttur.


15
Mmap () öğesinin her zaman okunan () öğeden daha hızlı olmadığını unutmayın. Sıralı okumalar için, mmap () size ölçülebilir bir avantaj sağlamaz - bu ampirik ve teorik kanıtlara dayanır. Bana inanmıyorsanız, kendi testinizi yazın.
Tim Cooper

1
Projemizden gelen sayıları, cümle veritabanı için bir tür metin dizini verebilirim. Dizin birkaç Gigabyte büyük ve anahtarlar üçlü bir ağaçta tutulur. Dizin hala okuma erişimine paralel olarak büyüyor, eşlenen parçaların dışına erişim ile yapılıyor pread. Solaris 9 Sparc'da (V890) pread erişimi mmap'inkinden 2 ila 3 kat daha yavaştır memcpy. Ancak sıralı erişimin daha hızlı olması gerekmiyor.
Patrick Schlüter

19
Biraz nitpick. Çağrı mekanizması gibi çalışmaz, çağrı mekanizmasıdır. Bir dosyayı eşlemek, anonim takas dosyası yerine bir dosyaya bellek alanı atar.
Patrick Schlüter

2

Henüz listelenmeyen bir avantaj, mmap()salt okunur bir eşlemeyi temiz sayfalar olarak tutabilmektir . Biri işlemin adres alanında bir read()arabellek ayırırsa, bir dosyadan arabelleği doldurmak için kullanırsa , bu arabelleğe karşılık gelen bellek sayfaları yazıldığından beri artık kirli olur.

Kirli sayfalar çekirdek tarafından RAM'den atılamaz. Takas alanı varsa, takas için çağrılabilirler. Ancak bu maliyetlidir ve sadece flash belleğe sahip küçük gömülü cihazlar gibi bazı sistemlerde hiçbir takas yoktur. Bu durumda, arabellek, işlem sonlanıncaya veya geri getirilinceye kadar RAM'de sıkışır madvise().

mmap()Sayfalara yazılmamış temiz. Çekirdeğin RAM'e ihtiyacı varsa, bunları bırakabilir ve sayfaların bulunduğu RAM'i kullanabilir. Eşleme işlemi tekrar erişirse, çekirdek, sayfaları orijinal olarak geldikleri dosyadan yeniden yükler. . Aynı şekilde, ilk etapta dolduruldular.

Bu, avantaj sağlamak için eşlenen dosyayı kullanan birden fazla işlem gerektirmez.


Çekirdek, önce içeriğini alttaki dosyaya yazarak 'kirli' bir mmap'd sayfası bırakamaz mı?
Jeremy Friesner

2
Kullanırken read(), sonunda verilerin yerleştirildiği sayfaların geldikleri dosyayla hiçbir ilişkisi yoktur. Yani yer değiştirmeleri dışında bunlar yazılamaz. Bir dosya ise mmap()ed(salt okunur aksine) ve yazılır ve haritalama yazılabilir olduğunu, o zaman haritalama oldu bağlıdır MAP_SHAREDya MAP_PRIVATE. Paylaşılan bir eşleme dosyaya yazılabilir / yazılabilir, ancak özel bir dosya yazılamaz.
TrentP
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.