मुझे फ़ाइल एक्सेस के लिए एमएमएपी का उपयोग कब करना चाहिए?


276

POSIX वातावरण फ़ाइलों तक पहुँचने के कम से कम दो तरीके प्रदान करता है। वहाँ मानक सिस्टम कॉल है open(), read(), write(), और दोस्तों, लेकिन वहां भी उपयोग करने का विकल्प है mmap()आभासी स्मृति में फ़ाइल मैप करने के लिए।

जब एक दूसरे के ऊपर प्रयोग करना बेहतर होता है? उनके व्यक्तिगत लाभ क्या हैं जो दो इंटरफेस सहित योग्यता रखते हैं?


16
यह भी देखें mmap () पढ़ने ब्लॉक बनाम और इस पोस्ट वहाँ जवाब में से एक में संदर्भित लिनुस टोर्वाल्ड द्वारा।
MvG

जवाबों:


299

mmapयदि आप एक ही फ़ाइल से केवल पढ़ने के फैशन में डेटा तक पहुँचने के लिए कई प्रक्रियाएँ करते हैं, तो यह बहुत अच्छा है, जो कि मेरे द्वारा लिखी जाने वाली सर्वर प्रणालियों में सामान्य है। mmapउन सभी प्रक्रियाओं को एक ही भौतिक मेमोरी पेज को साझा करने की अनुमति देता है, जिससे बहुत सारी मेमोरी बचती है।

mmapपेजिंग संचालन को अनुकूलित करने के लिए ऑपरेटिंग सिस्टम को भी अनुमति देता है। उदाहरण के लिए, दो कार्यक्रमों पर विचार करें; वह प्रोग्राम Aजो किसी 1MBफाइल में बफर बनाने के साथ पढ़ता है malloc, और प्रोग्राम B जिसे mmaps1MB फाइल मेमोरी में रखता है। यदि ऑपरेटिंग सिस्टम को Aमेमोरी मेमोरी का कुछ भाग स्वैप करना है, तो उसे मेमोरी को पुनः उपयोग करने से पहले बफर की सामग्री को स्वैप करना होगा। में Bके मामले में किसी भी असंशोधित mmapओएस जानता है क्योंकि कैसे मौजूदा फ़ाइल वे थे से उन्हें बहाल करने के लिए 'घ पृष्ठ तुरंत पुन: उपयोग किया जा सकता है mmap' से डी। (OS यह पता लगा सकता है कि शुरू में लिखने योग्य mmap'd' पृष्ठों को चिन्हित करके कौन से पृष्ठ अनमॉडिफाइड हैं और कॉपी स्ट्रैटजी के समान, सेग दोष को पकड़ सकते हैं )।

mmapअंतर प्रक्रिया संचार के लिए भी उपयोगी है । आप उन mmapफ़ाइलों को पढ़ / लिख सकते हैं, जिन्हें उस प्रक्रिया में लिखना है और फिर उस mmap'dक्षेत्र में सिंक्रोनाइज़ेशन प्राइमेटिव्स का उपयोग करना है (यह वही है जो MAP_HASSEMAPHOREझंडा है)।

एक जगह mmapअजीब हो सकती है यदि आपको 32 बिट मशीन पर बहुत बड़ी फ़ाइलों के साथ काम करने की आवश्यकता है। ऐसा इसलिए है क्योंकि mmapआपकी प्रक्रिया के पते स्थान में पते का एक सन्निहित ब्लॉक ढूंढना पड़ता है जो फ़ाइल की पूरी रेंज को मैप करने के लिए पर्याप्त है। यह एक समस्या बन सकती है यदि आपका पता स्थान खंडित हो जाता है, जहां आपके पास 2 जीबी पता स्थान खाली हो सकता है, लेकिन इसकी कोई भी व्यक्तिगत श्रेणी 1 जीबी फ़ाइल मैपिंग में फिट नहीं हो सकती है। इस मामले में आपको फ़ाइल को छोटे हिस्से में मैप करना पड़ सकता है, जितना आप इसे फिट बनाना चाहते हैं।

mmapपढ़ने / लिखने के प्रतिस्थापन के रूप में एक और संभावित अजीबता यह है कि आपको पृष्ठ आकार के ऑफसेट पर अपनी मैपिंग शुरू करनी होगी। यदि आप ऑफसेट पर कुछ डेटा प्राप्त करना चाहते हैं, तो आपको Xउस ऑफसेट को ठीक करना होगा ताकि यह संगत हो mmap

और अंत में, पढ़ना / लिखना एकमात्र तरीका है जिससे आप कुछ प्रकार की फ़ाइलों के साथ काम कर सकते हैं। पाइप और ट्टीmmap जैसी चीजों पर इस्तेमाल नहीं किया जा सकता है ।


10
क्या आप उन फ़ाइलों पर mmap () का उपयोग कर सकते हैं जो बढ़ रही हैं? या उस बिंदु पर आकार निर्धारित किया जाता है जब आप mmap () मेमोरी / फ़ाइल आवंटित करते हैं?
जोनाथन लेफ़लर

29
जब आप mmap कॉल करते हैं तो आपको एक आकार निर्दिष्ट करना होता है। इसलिए अगर आप टेल ऑपरेशन जैसा कुछ करना चाहते हैं तो यह बहुत उपयुक्त नहीं है।
डॉन नेफेल्ड

5
अफाक MAP_HASSEMAPHOREबीएसडी के लिए विशिष्ट है।
पैट्रिक शाल्टर

6
@JonathanLeffler निश्चित रूप से आप बढ़ती फ़ाइलों पर mmap () का उपयोग कर सकते हैं, लेकिन आपको mmap () को नए आकार के साथ फिर से कॉल करना होगा जब फ़ाइल आपके द्वारा शुरू की गई जगह की सीमा तक पहुंच जाती है। LevelDB का PosixMmapFile आपको एक अच्छा उदाहरण देता है। लेकिन उसने 1.15 से mmap का उपयोग बंद कर दिया। आप पुराने संस्करण Github
baotiao

4
यदि किसी फ़ाइल को कई पास में संसाधित करने की आवश्यकता होती है, तो mmap उपयोगी हो सकता है: वर्चुअल मेमोरी पेज आवंटित करने की लागत केवल एक बार भुगतान की जाती है।
जिब

69

एक क्षेत्र जहां मुझे मिलीप () का फायदा नहीं हुआ, वह थी छोटी फाइलें (16K के तहत) पढ़ना। पूरी फ़ाइल को पढ़ने के लिए पेज फॉल्टिंग का ओवरहेड केवल एक रीड () सिस्टम कॉल करने की तुलना में बहुत अधिक था। इसका कारण यह है कि कर्नेल कभी-कभी आपके समय के स्लाइस में पूरी तरह से एक रीडिज़ाइन कर सकता है, जिसका अर्थ है कि आपका कोड स्विच नहीं करता है। पृष्ठ दोष के साथ, यह अधिक संभावना थी कि एक और कार्यक्रम निर्धारित किया जाएगा, जिससे फ़ाइल संचालन में एक उच्च विलंबता होगी।


4
+1 मैं इसकी पुष्टि कर सकता हूं। छोटी फ़ाइलों के लिए यह mallocमेमोरी का एक टुकड़ा और readइसमें 1 बनाने के लिए तेज़ है। यह वही कोड रखने की अनुमति देता है जो मेमोरी मैप्स को हैंडल करता है।
पैट्रिक श्ल्टर

35
इसने कहा, इसके लिए आपका औचित्य सही नहीं है। अनुसूचक के पास अंतर के साथ करने के लिए कुछ भी नहीं है। अंतर लिखने की पहुंच से लेकर पेज टेबल तक होता है, जो कि कर्नेल की एक वैश्विक संरचना होती है जो यह बताती है कि कौन सी प्रक्रिया किस मेमोरी पेज और उसके एक्सेस अधिकारों को रखती है। यह ऑपरेशन बहुत महंगा हो सकता है (यह कैशे लाइनों पर आक्रमण कर सकता है, यह दूर टीएलबी के माध्यम से हो सकता है, तालिका वैश्विक है इसलिए समवर्ती पहुंच आदि के खिलाफ संरक्षित किया जाना है)। आपको मानचित्र के एक निश्चित आकार की आवश्यकता है ताकि readएक्सेस का ओवरहेड वर्चुअल मेमोरी हेरफेर के ओवरहेड से अधिक हो।
पैट्रिक शाल्टर

1
@ PatrickSchlüter ठीक है, मैं समझता हूं कि mmap () की शुरुआत में ओवरहेड है जिसमें पेज टेबल को संशोधित करना शामिल है। मान लें कि हम 16K फाइल को मेमोरी में मैप करते हैं। 4K के पेज साइज के mmapलिए, पेज टेबल में 4 एंट्री को अपडेट करना होता है। लेकिन read16K के बफर में कॉपी करने के लिए 4 पेज टेबल प्रविष्टियों को अपडेट करना भी शामिल है, यह उल्लेख करने के लिए कि उपयोगकर्ता एड्र स्पेस में 16K को कॉपी करने की आवश्यकता नहीं है। तो क्या आप पेज टेबल पर परिचालन के अंतर के बारे में विस्तार से बता सकते हैं, और यह कैसे अधिक महंगा है mmap?
flow2k

45

mmapजब आपके पास बड़ी फ़ाइलों पर रैंडम एक्सेस हो तो फायदा होगा। एक अन्य लाभ यह है कि आप इसे बफ़रिंग से परेशान किए बिना, मेमोरी ऑपरेशंस (मेमसीपी, पॉइंटर अंकगणित) के साथ एक्सेस करते हैं। सामान्य आई / ओ कभी-कभी बफ़र्स का उपयोग करते समय काफी मुश्किल हो सकता है जब आपके बफर से बड़ी संरचनाएं होती हैं। कोड को संभालने के लिए जो अक्सर सही होना मुश्किल होता है, आम तौर पर मिमीप आसान होता है। इसने कहा, काम करने के दौरान कुछ निश्चित जाल होते हैं mmap। जैसा कि लोगों ने पहले ही उल्लेख किया है, mmapस्थापित करने के लिए काफी महंगा है, इसलिए यह केवल दिए गए आकार (मशीन से मशीन तक भिन्न) के लिए उपयोग करने के लायक है।

फ़ाइल के लिए शुद्ध अनुक्रमिक पहुँच के लिए, यह हमेशा बेहतर समाधान नहीं होता है, हालांकि madviseसमस्या को कम करने के लिए एक उपयुक्त कॉल हो सकती है।

आपको अपने आर्किटेक्चर (SPARC, itanium) के संरेखण प्रतिबंधों से सावधान रहना होगा, IO लिखने / लिखने के साथ बफ़र्स को अक्सर ठीक से संरेखित किया जाता है और जब एक कास्टेड पॉइंटर को डीफ़र करना होता है तो वे फंसते नहीं हैं।

आपको इस बात का भी ध्यान रखना होगा कि आप नक्शे से बाहर न पहुँचें। यह आसानी से हो सकता है यदि आप अपने नक्शे पर स्ट्रिंग फ़ंक्शन का उपयोग करते हैं, और आपकी फ़ाइल में अंत में एक \ 0 नहीं होता है। यह ज्यादातर उस समय काम करेगा जब आपकी फ़ाइल का आकार पृष्ठ आकार का एक से अधिक न हो क्योंकि अंतिम पृष्ठ 0 से भरा हुआ है (मैप किया गया क्षेत्र हमेशा आपके पृष्ठ आकार के कई के आकार में होता है)।


30

अन्य अच्छे उत्तरों के अलावा, Google के विशेषज्ञ रॉबर्ट लव द्वारा लिखित लिनक्स सिस्टम प्रोग्रामिंग का एक उद्धरण :

के फायदे mmap( )

mmap( )मानक read( )और write( )सिस्टम कॉल के माध्यम से मुट्ठी भर फाइलों में कई फायदे हैं। उनमें से हैं:

  • मेमोरी-मैप की गई फ़ाइल से पढ़ने और लिखने से उस एक्स्ट्रॉन्स कॉपी से बचा जाता है जो read( )या write( )सिस्टम कॉल का उपयोग करते समय होती है , जहाँ डेटा को उपयोगकर्ता-स्पेस बफर से कॉपी किया जाना चाहिए।

  • किसी भी संभावित पृष्ठ दोषों के अलावा, मेमोरी-मैप की गई फ़ाइल से पढ़ना और लिखना किसी भी सिस्टम कॉल या संदर्भ स्विच को ओवरहेड नहीं करता है। यह मेमोरी एक्सेस करने जितना आसान है।

  • जब कई प्रक्रियाएं एक ही ऑब्जेक्ट को मेमोरी में मैप करती हैं, तो डेटा सभी प्रक्रियाओं के बीच साझा किया जाता है। केवल-पढ़ने के लिए और साझा किए जाने योग्य लेखन उनकी संपूर्णता में साझा किए जाते हैं; निजी लेखन योग्य मैपिंग में उनके अभी तक नहीं हैं-गाय (कॉपी-ऑन-राइट) पेज साझा किए गए हैं।

  • मैपिंग के आसपास की तलाश में तुच्छ सूचक जोड़-तोड़ शामिल हैं। lseek( )सिस्टम कॉल की कोई आवश्यकता नहीं है ।

इन कारणों के लिए, mmap( )कई अनुप्रयोगों के लिए एक स्मार्ट विकल्प है।

का नुकसान mmap( )

उपयोग करते समय ध्यान में रखने के लिए कुछ बिंदु हैं mmap( ):

  • मेमोरी मैपिंग हमेशा आकार में पृष्ठों की एक पूर्णांक संख्या होती है। इस प्रकार, बैकिंग फ़ाइल के आकार और पृष्ठों की पूर्णांक संख्या के बीच का अंतर सुस्त स्थान के रूप में "व्यर्थ" है। छोटी फ़ाइलों के लिए, मैपिंग का एक महत्वपूर्ण प्रतिशत बर्बाद हो सकता है। उदाहरण के लिए, 4 केबी पेज के साथ, एक 7 बाइट मैपिंग में 4,089 बाइट्स बर्बाद होते हैं।

  • मैमोरी मैपिंग प्रक्रिया के पते की जगह में फिट होनी चाहिए। 32-बिट एड्रेस स्पेस के साथ, विभिन्न आकार के मैपिंग की एक बड़ी संख्या के परिणामस्वरूप एड्रेस स्पेस का विखंडन हो सकता है, जिससे बड़े मुक्त सन्निहित क्षेत्रों को खोजना मुश्किल हो जाता है। यह समस्या, ज़ाहिर है, 64-बिट एड्रेस स्पेस के साथ बहुत कम स्पष्ट है।

  • कर्नेल के अंदर मेमोरी मैपिंग और संबंधित डेटा संरचनाओं को बनाने और बनाए रखने में ओवरहेड होता है। इस ओवरहेड को आम तौर पर पिछली अनुभाग में उल्लिखित डबल कॉपी के उन्मूलन द्वारा माना जाता है, विशेष रूप से बड़ी और अक्सर एक्सेस की गई फ़ाइलों के लिए।

इन कारणों से, mmap( )मैप किए गए फ़ाइल के बड़े होने पर सबसे अधिक लाभ का एहसास होता है (और इस प्रकार कोई भी व्यर्थ जगह कुल मैपिंग का एक छोटा प्रतिशत है), या जब मैप की गई फ़ाइल का कुल आकार पृष्ठ के आकार से समान रूप से विभाज्य हो ( और इस प्रकार कोई व्यर्थ जगह नहीं है)।


13

मेमोरी मैपिंग में पारंपरिक IO की तुलना में भारी गति लाभ की संभावना है। यह ऑपरेटिंग सिस्टम को सोर्स फाइल से डेटा पढ़ने की सुविधा देता है क्योंकि मेमोरी मैप्ड फाइल में पेज टच होते हैं। यह फ़ॉल्टिंग पेज बनाकर काम करता है, जिसे OS पता लगाता है और फिर OS फ़ाइल से संबंधित डेटा को स्वचालित रूप से लोड करता है।

यह पेजिंग तंत्र की तरह ही काम करता है और आमतौर पर सिस्टम पेज की सीमाओं और आकार (आमतौर पर 4K) पर डेटा पढ़कर उच्च गति I / O के लिए अनुकूलित किया जाता है - एक आकार जिसके लिए अधिकांश फ़ाइल सिस्टम कैश को अनुकूलित किया जाता है।


15
ध्यान दें कि mmap () हमेशा पढ़ने की तुलना में तेज़ नहीं होता है ()। अनुक्रमिक रीड्स के लिए, एमएमएपी () आपको कोई औसत दर्जे का लाभ नहीं देगा - यह अनुभवजन्य और सैद्धांतिक साक्ष्य पर आधारित है। यदि आप मुझ पर विश्वास नहीं करते हैं, तो अपना परीक्षण लिखें।
टिम कूपर

1
मैं हमारी परियोजना से आने वाले नंबर दे सकता हूं, एक वाक्यांश डेटाबेस के लिए एक प्रकार का पाठ सूचकांक। सूचकांक कई गीगाबाइट बड़ा है और चाबियाँ एक टर्नरी पेड़ में आयोजित की जाती हैं। सूचकांक अभी भी पढ़ने के लिए समानांतर में बढ़ रहा है, मैप किए गए हिस्सों के बाहर पहुंच के माध्यम से किया जाता है pread। सोलारिस 9 स्पार्क (V890) पर पैम्ड की पहुंच मिमीप की तुलना में 2 से 3 गुना धीमी है memcpy। लेकिन आप सही हैं कि अनुक्रमिक पहुंच आवश्यकता से अधिक तेज नहीं है।
पैट्रिक श्ल्टर

19
बस थोड़ा सा नाइटपिक। यह पेजिंग तंत्र की तरह काम नहीं करता है, यह पेजिंग तंत्र है। फ़ाइल को मैप करना अनाम स्वैप फ़ाइल के बजाय एक मेमोरी क्षेत्र को फ़ाइल में असाइन कर रहा है।
पैट्रिक श्ल्टर

2

एक लाभ जो अभी तक सूचीबद्ध नहीं है, वह है mmap()केवल साफ - सुथरे पन्नों के रूप में एक मैपिंग की क्षमता । यदि कोई प्रक्रिया के पता स्थान में एक बफर आवंटित करता है, तो read()एक फ़ाइल से बफर को भरने के लिए उपयोग करता है, उस बफर के संगत मेमोरी पेज अब गंदे हैं क्योंकि उन्हें लिखा गया है।

कर्नेल द्वारा डर्टी पेज को रैम से नहीं हटाया जा सकता है। यदि स्वैप स्थान है, तो उन्हें स्वैप करने के लिए बाहर रखा जा सकता है। लेकिन यह महंगा है और कुछ प्रणालियों पर, जैसे कि केवल फ्लैश मेमोरी वाले छोटे एम्बेडेड डिवाइस, कोई स्वैप नहीं है। उस स्थिति में, बफर रैम में फंस जाएगा जब तक कि प्रक्रिया से बाहर नहीं निकल जाता है, या शायद इसे वापस देता है madvise()

mmap()पन्नों पर लिखे गैर साफ हैं। यदि कर्नेल को RAM की आवश्यकता होती है, तो यह बस उन्हें ड्रॉप कर सकता है और उन RAM का उपयोग कर सकता है जो पृष्ठ अंदर थे। यदि मानचित्रण की प्रक्रिया फिर से उस तक पहुंचती है, तो यह पृष्ठ दोष का कारण बनता है, कर्नेल उन पृष्ठों से पृष्ठों को फिर से लोड करता है, जो वे मूल रूप से आए थे। । उसी तरह वे पहले स्थान पर आबाद थे।

यह लाभ के लिए मैप की गई फ़ाइल का उपयोग करके एक से अधिक प्रक्रिया की आवश्यकता नहीं है।


क्या कर्नेल किसी 'गंदे' mmap'd पेज को पहले अंतर्निहित फ़ाइल के लिए अपनी सामग्री लिखकर नहीं छोड़ सकता है?
जेरेमी फ्राइसनर

2
उपयोग करते समय read(), जिन पृष्ठों पर डेटा डाला जाता है, उनका उस फाइल से कोई संबंध नहीं होता है, जो वे ले सकते हैं। इसलिए उन्हें स्वैप स्पेस के अलावा बाहर नहीं लिखा जा सकता है। यदि कोई फ़ाइल है mmap()ed, और मैपिंग लेखन योग्य है (जैसा कि केवल पढ़ने के लिए विरोध किया जाता है), और लिखा जाता है, तो यह इस बात पर निर्भर करता है कि मैपिंग थी MAP_SHAREDया MAP_PRIVATE। एक साझा मानचित्रण फ़ाइल में लिखा जा सकता है, लेकिन एक निजी नहीं हो सकता है।
ट्रेंटपी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.