2013-09-03 5 views
7

मैं निम्नलिखित समस्या है के साथ एक बड़े स्मृति मानचित्रण:शून्य `madvise`

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

इसे जल्दी से करने की सबसे अच्छी रणनीति क्या है?

विल

madvise(ptr, length, MADV_DONTNEED); 

गारंटी मुझे उस किसी भी बाद पहुंच नया रिक्त पृष्ठ प्रदान करते हैं?

लिनक्स man madvise इस पृष्ठ से:

इस कॉल (MADV_DONTNEED के मामले को छोड़कर) आवेदन के शब्दों को प्रभावित नहीं करता है, लेकिन इसके प्रदर्शन को प्रभावित कर सकते हैं। कर्नेल सलाह को अनदेखा करने के लिए स्वतंत्र है।

...

MADV_DONTNEED

इस रेंज सफल होगा में पृष्ठों के बाद पहुंच, लेकिन या तो अंतर्निहित मैप की फ़ाइल से स्मृति सामग्री के फिर से लोड करने में परिणाम होगा (mmap को देखने के (2)) या अंतर्निहित फ़ाइल के बिना मैपिंग के लिए शून्य-भर-ऑन-डिमांड पेज।

...

वर्तमान लिनक्स कार्यान्वयन (2.4.0) विचार इस प्रणाली कॉल सलाह के रूप में की तुलना में एक आदेश के रूप में अधिक ...

या मैं munmap करने के लिए है और इस क्षेत्र को पुन: मैप करना नए सिरे से?

यह लिनक्स पर काम करते हैं और आदर्श ओएस एक्स

+0

मेरे पास इसका परीक्षण करने का कोई तरीका नहीं है, लेकिन एफडब्ल्यूआईडब्ल्यू, [ओएसएक्स] (https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man2/madvise.2। एचटीएमएल) मैन पेज में 'madvise'd पेज शून्य होने के बारे में कुछ भी उल्लेख नहीं है। [Posix] (http://pubs.opengroup.org/onlinepubs/009695399/functions/posix_madvise.html) संस्करण या तो नहीं है। मेमोरी स्पेस को फिर से मैप करने के लिए ओवरहेड विशाल है? – Collin

+0

@ कोलिन यह अत्यधिक प्रदर्शन के रूप में नहीं है, लेकिन मुझे अपने धागे को निलंबित करने की आवश्यकता होगी और यदि आवश्यक हो तो पॉइंटर को नए मैपिंग में अपडेट करें। यह अधिक समानांतर कोड है जो गलत हो सकता है ... और मैं उत्सुक हूं कि यह कॉल वास्तव में कैसे काम करता है। –

उत्तर

7

वहाँ आपकी समस्या का एक बहुत आसान समाधान है कि काफी पोर्टेबल है:

mmap(ptr, length, PROT_READ|PROT_WRITE, MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); 

MAP_FIXED के बाद से काफी मनमाने ढंग से कार्यान्वयन-विशिष्ट कारणों से विफल करने के लिए, memset पर वापस गिरने की अनुमति दी है अगर यह रिटर्न MAP_FAILED उचित होगा ।

+0

धन्यवाद, यह वही है जो मैं ढूंढ रहा था। यह मेरे ओएस एक्स पर भी काम करता है। –

+3

यदि यह स्पष्ट नहीं है, तो विचार है कि एमएएम_एफएक्सएड पते के साथ 'mmap()' को फिर से शुरू किया जाए, जो पूर्व-मिमी वाली मेमोरी के भाग (या पूरे) को इंगित करता है। प्रलेखन के अनुसार, यह पिछले पृष्ठों को फेंक देगा, और नए ताजा पृष्ठों को मैप किया जाएगा। –

+0

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

1

यह madvise व्यवहार निश्चित रूप से मानक नहीं है पर एक ही व्यवहार होता है, इसलिए तो यह पोर्टेबल नहीं होगा।

यदि आप जिस हिस्से को शून्य करना चाहते हैं, वह आपके मैपिंग के अंत में होता है तो आप ftruncate से दूर हो सकते हैं।आप एक कदम और अधिक लागू करने के लिए होगा:

  1. shm_open अपने डेटा के लिए एक "लगातार" फ़ाइल वर्णनकर्ता के लिए
  2. जरूरत आकार
  3. कि एफडी की mmap को ftruncate

फिर आप हमेशा

  1. munmap
  2. कम
  3. ftruncate वास्तविक लंबाई के लिए कुछ करने के लिए ftruncate आप
  4. mmap जरूरत है फिर से

और फिर भाग है कि आप "पुनः मानचित्रित" शून्य से आरंभ होगा।

लेकिन यह भी ध्यान में रखें कि सिस्टम को पृष्ठों का शून्यकरण करना है। यह इनलाइन सामग्री की तुलना में थोड़ा अधिक कुशल हो सकता है कि आपका कंपाइलर memset के लिए उत्पादित करता है, लेकिन यह सुनिश्चित नहीं है।

+0

मुझे बस पूरे मानचित्रण को शून्य करने की आवश्यकता है, लंबाई वही रहती है। अगर मैं 'मुनमाप' आईडी से गुजरना चाहता हूं तो बस 'मुनमैप', 'एमएमएपी/एमएपी_एएनओएनएमओयूएस' पर कॉल करें। इसे जटिल करने की कोई ज़रूरत नहीं है। जो मैं वास्तव में करना चाहता हूं वह उस चरण से गुज़रना नहीं है जहां वीएम स्पेस अस्थायी रूप से अप्रयुक्त है, लेकिन यदि पृष्ठ गंदे हैं और आदर्श रूप से भौतिक RAM को तब तक रिलीज़ नहीं किया जाता है जब तक इसका पुन: उपयोग नहीं किया जाता है। –

+1

'munmap' के बाद 'mmap' सुरक्षित नहीं है। इसमें दौड़ की स्थिति है; सीमा को समय-समय पर अनैप किया जाएगा और एक अन्य थ्रेड क्षेत्र में मैपिंग प्राप्त कर सकता है, या केवल क्षेत्र तक पहुंचने की कोशिश से segfault प्राप्त कर सकता है। एक सुरक्षित दृष्टिकोण के लिए मेरा जवाब देखें। –

+0

@ आर .., सवाल धागे का जिक्र नहीं है। लेकिन निश्चित रूप से, यदि आप अपने पैरों के नीचे मैपिंग बदलते हैं, तो आपको यह सुनिश्चित करना होगा कि कोई अन्य धागा इसका उपयोग नहीं कर रहा है। यदि यह एप्लिकेशन से स्पष्ट नहीं है तो इसे किसी प्रकार के लॉकिंग द्वारा सुनिश्चित किया जाना होगा। लेकिन यह सवाल से परे चला जाता है क्योंकि यह सामने आया है।आपके समाधान का नुकसान यह है कि यह कार्यान्वयन विशिष्ट व्यवहार पर निर्भर करता है। –

1

लिनक्स पर, आप मैपिंग शून्य करने वाले अज्ञात मैपिंग पर MADV_DONTNEED पर भरोसा कर सकते हैं। यह पोर्टेबल नहीं है, हालांकि - madvise() स्वयं मानकीकृत नहीं है। posix_madvise() मानकीकृत है, लेकिन POSIX_MADV_DONTNEED समान व्यवहार है क्योंकि लिनक्स MADV_DONTNEED ध्वज - posix_madvise() हमेशा सलाहकार है, और एप्लिकेशन के अर्थशास्त्र को प्रभावित नहीं करता है।

संबंधित मुद्दे