2013-08-29 13 views
13

यह एक पोस्ट है जो this comment से प्रेरित है, जिसमें सीपीथॉन में ऑब्जेक्ट्स के लिए स्मृति आवंटित की जाती है। मूल रूप से, यह एक सूची बनाने और एक लूप में एक सूची बनाने के संदर्भ में एक सूची समझ के साथ के संदर्भ में था।सीपीथन स्मृति आवंटन

  1. कितने अलग अलग allocaters CPython में देखते हैं:

    तो यहाँ मेरी सवाल कर रहे हैं?

    • प्रत्येक का कार्य क्या है?
  2. malloc एक बार कहा जाता है? (एक सूची समझ malloc के लिए एक कॉल के आधार पर न मिले क्या this comment
  3. में कही गई सारी कितना स्मृति अजगर स्टार्टअप पर खुद के लिए आवंटित करता है?
    1. देखते हैं शासी जो डेटा संरचनाओं पहले मिल "झलक" नियम इस स्मृति पर?
  4. किसी ऑब्जेक्ट द्वारा हटाए जाने वाले स्मृति द्वारा उपयोग की जाने वाली मेमोरी का क्या होता है (क्या पाइथन अभी भी भविष्य में किसी अन्य ऑब्जेक्ट को आवंटित करने के लिए स्मृति को पकड़ता है, या जीसी मेमोरी को मुक्त करता है एक और प्रक्रिया, Google क्रोम का उपयोग करने के लिए कहें)?
  5. व्हील एन एक जीसी ट्रिगर किया गया है?
  6. list एस गतिशील सरणी हैं, जिसका अर्थ है कि उन्हें स्मृति के एक संगत टुकड़े की आवश्यकता है। इसका अर्थ यह है कि यदि मैं किसी ऑब्जेक्ट को किसी सूची में जोड़ने का प्रयास करता हूं, जिसका अंतर्निहित-सी-डेटा-स्ट्रक्चर सरणी विस्तारित नहीं किया जा सकता है, तो सरणी को स्मृति के एक अलग भाग पर कॉपी किया जाता है, जहां एक बड़ा संगत ब्लॉक उपलब्ध होता है। तो जब मैं एक सूची शुरू करता हूं तो इस सरणी में कितनी जगह आवंटित की जाती है?
    • नई सरणी को कितनी अतिरिक्त जगह आवंटित की जाती है, जिसमें अब पुरानी सूची और संलग्न वस्तु है?

संपादित: टिप्पणियों से, मैं इकट्ठा वहाँ अभी तक भी कई सवाल यहाँ हैं कि। मैंने केवल यही किया क्योंकि ये प्रश्न सभी सुंदर हैं। फिर भी, अगर यह मामला है तो मुझे इसे कई पदों में विभाजित करने में खुशी होगी (कृपया मुझे टिप्पणियों में ऐसा करने के लिए बताएं)

+3

डाउनवोट क्यों? मैं एक कानूनी सवाल देखता हूं कि एक बार मूर्ख नहीं है, बेवकूफ़ है। – RickyA

+0

शायद क्योंकि यह अविश्वसनीय रूप से व्यापक है। यहां कम से कम 6 प्रश्न हैं। – user2357112

+1

सीपीआई दस्तावेज के [मेमोरी प्रबंधन] (http://docs.python.org/3/c-api/memory.html) अध्याय में इसका उत्तर दिया गया है। इसमें से कुछ आप से पूछ रहे हैं ("... कई ऑब्जेक्ट-विशिष्ट आवंटकों" आपको यह नहीं बताता कि कितने "कई" हैं), लेकिन आपको एक विशिष्ट संस्करण और डाइविंग चुनने के बिना और अधिक जानकारी नहीं मिल रही है कोड में – abarnert

उत्तर

19

इनमें से अधिकतर सीपीआई दस्तावेज के Memory Management अध्याय में उत्तर दिया गया है।

कुछ दस्तावेज जो आप पूछ रहे हैं उससे योनर है। अधिक जानकारी के लिए, आपको स्रोत कोड पर जाना होगा। और जब तक आप एक विशिष्ट संस्करण नहीं चुनते हैं तब तक कोई भी ऐसा करने के लिए तैयार नहीं होगा। (कम से कम 2.7.5, प्री-2.7.6, 3.3.2, प्री-3.3.3, और प्री-3.4 अलग-अलग लोगों के लिए दिलचस्प होगा।)

obmalloc.c फ़ाइल का स्रोत एक अच्छी प्रारंभिक जगह है

Object-specific allocators 
    _____ ______ ______  ________ 
    [ int ] [ dict ] [ list ] ... [ string ]  Python core   | 
+3 | <----- Object-specific memory -----> | <-- Non-object memory --> | 
    _______________________________  |       | 
    [ Python`s object allocator ]  |       | 
+2 | ####### Object memory ####### | <------ Internal buffers ------> | 
    ______________________________________________________________ | 
    [   Python`s raw memory allocator (PyMem_ API)   ] | 
+1 | <----- Python memory (under PyMem manager`s control) ------> | | 
    __________________________________________________________________ 
    [ Underlying general-purpose allocator (ex: C library malloc) ] 
0 | <------ Virtual memory allocated for the python process -------> | 

    ========================================================================= 
    _______________________________________________________________________ 
    [    OS-specific Virtual Memory Manager (VMM)    ] 
-1 | <--- Kernel dynamic storage allocation & management (page-based) ---> | 
    __________________________________ __________________________________ 
    [         ] [         ] 
-2 | <-- Physical memory: ROM/RAM --> | | <-- Secondary storage (swap) --> | 

कितने अलग अलग allocaters CPython में देखते हैं: अपने प्रश्नों, और शीर्ष पर टिप्पणी से कई के लिए एक अच्छी छोटी ASCII कला ग्राफ है?

दस्तावेज़ों के अनुसार, "कई"। आप बिल्टिन और stdlib प्रकारों में से किसी को गिन सकते हैं, फिर यदि आप वास्तव में चाहते थे तो सामान्य के मुट्ठी भर जोड़ें। लेकिन मुझे यकीन नहीं है कि यह आपको क्या बताएगा। (और यह बहुत संस्करण-विशिष्ट होगा। IIRC, यहां तक ​​कि 3.3 वृक्ष के भीतर बदल सही संख्या, के रूप में वहाँ है कि क्या नई शैली तार तीन अलग अलग allocators या एक का उपयोग करना चाहिए के साथ एक प्रयोग किया गया था।)


प्रत्येक का कार्य क्या है?

स्तर +3 पर ऑब्जेक्ट-विशिष्ट आवंटक विशिष्ट उपयोग मामलों के लिए हैं जो अनुकूलित करने योग्य हैं। डॉक्स के रूप में कहते हैं:

उदाहरण के लिए, पूर्णांक वस्तुओं तार, tuples या शब्दकोशों से ढेर के भीतर अलग ढंग से प्रबंधित क्योंकि पूर्णांकों अलग भंडारण आवश्यकताओं और गति/अंतरिक्ष समझौतों से संकेत कर रहे हैं।

कि नीचे, स्तर 2 पर विभिन्न सामान्य समर्थन allocators (और 1.5 और हो सकता है 2.5) कम से कम कम से एक वस्तु संभाजक, एक क्षेत्र संभाजक, और एक छोटे-ब्लॉक संभाजक, कर रहे हैं आदि-लेकिन सभी पहले निजी कार्यान्वयन विवरण हैं (जिसका मतलब सी-एपीआई तक भी निजी है; जाहिर है कि यह सब पाइथन कोड के लिए निजी है)।

और उसके नीचे, कच्चा आवंटक है, जिसका कार्य ओएस से अधिक स्मृति के लिए पूछना है जब उच्च स्तरीय आवंटकों को इसकी आवश्यकता होती है।


जब malloc acutally कहा जाता है?

कच्चे स्मृति allocator (या इसके ढेर प्रबंधक) केवल बात यह है कि कभी malloc कॉल किया जाना चाहिए। (वास्तव में, यह शायद malloc पर भी कॉल नहीं कर सकता है; यह mmap या VirtualAlloc जैसे कार्यों का उपयोग कर सकता है। लेकिन मुद्दा यह है कि यह एकमात्र चीज है जो कभी भी ओएस को स्मृति के लिए पूछती है।) पाइथन के मूल में कुछ अपवाद हैं , लेकिन वे शायद ही कभी प्रासंगिक होंगे।

दस्तावेज़ स्पष्ट रूप से कहते हैं कि उच्च स्तरीय कोड को malloc से प्राप्त स्मृति में पाइथन ऑब्जेक्ट्स पर काम करने की कोशिश नहीं करना चाहिए।

हालांकि, बहुत सारे stdlib और एक्सटेंशन मॉड्यूल हैं जो का उपयोग के साथ पायथन ऑब्जेक्ट्स के लिए करते हैं।

उदाहरण के लिए, 1000x1000 int32 मानों की एक numpy सरणी 1 मिलियन पायथन int एस आवंटित नहीं करती है, इसलिए इसे int आवंटक के माध्यम से जाना नहीं है। इसके बजाए, यह केवल malloc है जो 1 मिलियन सी int एस की सरणी है, और जब आप उन्हें एक्सेस करते हैं तो उन्हें पाइथन ऑब्जेक्ट्स में लपेटें।


कितना स्मृति अजगर स्टार्टअप पर खुद के लिए आवंटित करता है?

यह मंच-विशिष्ट है, और कोड से पता लगाने में थोड़ा मुश्किल है।हालांकि, जब मैं अपने 64-बिट मैक पर एक नया python3.3 दुभाषिया लॉन्च करता हूं, तो यह 13.1 एमबी वर्चुअल मेमोरी के साथ शुरू होता है, और लगभग तुरंत 201 एमबी तक फैलता है। तो, यह एक मोटा ballpark गाइड होना चाहिए।

क्या ऐसे नियम हैं जो इस संरचना पर डेटा संरचनाओं को पहले "डीआईबीएस" प्राप्त करते हैं?

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


जब यह हटा दी जाती है क्या एक वस्तु के द्वारा प्रयोग किया स्मृति के लिए होता (अजगर पर अभी भी याद करने के लिए भविष्य में किसी अन्य वस्तु के लिए आवंटित करने के लिए पकड़ है, या जीसी ऊपर किसी अन्य के लिए स्मृति मुक्त करता है प्रक्रिया का उपयोग करने के लिए Google क्रोम कहें)?

यह ऑब्जेक्ट-विशिष्ट आवंटक पर वापस जाता है, जो इसे एक फ्रीलिस्ट पर रख सकता है, या इसे कच्चे आवंटक को छोड़ सकता है, जो अपनी खुद की फ्रीलिस्ट रखता है। कच्चे आवंटक लगभग कभी ओएस को वापस स्मृति जारी करता है।

यह आमतौर पर कोई अच्छी याददाश्त एक आधुनिक ओएस के लिए वापस जारी करने के लिए कारण नहीं है क्योंकि वहाँ है। यदि आपके पास आस-पास के अप्रयुक्त पृष्ठों का एक टन है, तो ओएस का वीएम सिर्फ उन्हें बाहर कर देगा यदि किसी अन्य प्रक्रिया की आवश्यकता है। और जब एक अच्छा कारण है, तो यह लगभग हमेशा एप्लिकेशन-विशिष्ट होता है, और सबसे सरल समाधान आपकी विशाल अल्पकालिक स्मृति आवश्यकताओं को प्रबंधित करने के लिए एकाधिक प्रक्रियाओं का उपयोग करना है।


जब एक जीसी शुरू हो रहा है?

यह "जीसी" द्वारा आपके मतलब पर निर्भर करता है।

CPython refcounting उपयोग करता है; हर बार जब आप किसी ऑब्जेक्ट का संदर्भ जारी करते हैं (किसी चर या एक संग्रह में स्लॉट को पुन: जोड़कर, एक चर को दायरे से बाहर जाने दें, आदि), यदि यह अंतिम संदर्भ था, तो इसे तुरंत साफ़ कर दिया जाएगा। यह दस्तावेज़ों में Reference Counting अनुभाग में समझाया गया है।

हालांकि, वहाँ refcounting साथ एक समस्या है: दो वस्तुओं एक दूसरे के संदर्भ अगर, तब भी जब सब बाहर संदर्भ चले जाओ, वे अभी भी साफ नहीं किया जाएगा। इसलिए, सीपीथन में हमेशा एक चक्र कलेक्टर होता है जो समय-समय पर ऑब्जेक्ट्स के चक्रों की तलाश में वस्तुओं को चलाता है जो एक-दूसरे को संदर्भित करते हैं, लेकिन कोई बाहरी संदर्भ नहीं है। (यह थोड़ा और जटिल है, लेकिन यह मूल विचार है।) gc मॉड्यूल के लिए दस्तावेज़ों में यह पूरी तरह से समझाया गया है। कलेक्टर तब चला सकता है जब आप इसे स्पष्ट रूप से पूछते हैं, जब फ्रीलिस्ट कम हो रहे हैं, या जब यह लंबे समय तक नहीं चलता है; यह गतिशील है और कुछ हद तक विन्यास योग्य है, इसलिए "कब" के लिए एक विशिष्ट उत्तर देना मुश्किल है।


सूचियों गतिशील सरणियों, जो वे स्मृति का एक सन्निहित टुकड़ा की जरूरत का मतलब है। इसका अर्थ यह है कि यदि मैं किसी ऑब्जेक्ट को किसी सूची में जोड़ने का प्रयास करता हूं, जिसका अंतर्निहित-सी-डेटा-स्ट्रक्चर सरणी विस्तारित नहीं किया जा सकता है, तो सरणी को स्मृति के एक अलग भाग पर कॉपी किया जाता है, जहां एक बड़ा संगत ब्लॉक उपलब्ध होता है। तो जब मैं एक सूची शुरू करता हूं तो इस सरणी में कितनी जगह आवंटित की जाती है?

इसके लिए कोड अधिकतर listobject.c के अंदर है।यह जटिल है; अस्थायी इंटरमीडिएट सूचियां बनाने और गैर-इन-प्लेस सॉर्टिंग के लिए टाइम्सोर्ट द्वारा उपयोग किए जाने वाले कोड जैसे विशेष मामलों का एक गुच्छा है। लेकिन आखिरकार, कोड का कुछ टुकड़ा तय करता है कि उसे एन पॉइंटर्स के लिए कमरे की जरूरत है।

यह भी विशेष रूप से दिलचस्प नहीं है। अधिकांश सूचियां या तो कभी भी विस्तारित नहीं होती हैं, या मूल आकार से कहीं अधिक विस्तारित नहीं होती हैं, इसलिए प्रारंभिक सूचियों के लिए स्टार्ट अपशिष्ट मेमोरी पर अतिरिक्त आवंटन करना और सबसे बढ़ती सूचियों के लिए बहुत मदद नहीं करता है। तो, पायथन इसे रूढ़िवादी खेलता है। मेरा मानना ​​है कि यह अपने आंतरिक फ्रीलिस्ट को देखकर शुरू होता है जो एन पॉइंटर्स से बहुत बड़ा नहीं है (यह आसन्न मुक्त सूची भंडारण को भी समेकित कर सकता है; मुझे नहीं पता कि यह क्या करता है), इसलिए यह कभी-कभी थोड़ा सा आवंटित हो सकता है, लेकिन आम तौर पर यह ऐसा नहीं करता। सटीक कोड PyList_New में होना चाहिए।

किसी भी दर पर, यदि सूची आवंटक के फ्रीलिस्ट में कोई जगह नहीं है, तो यह ऑब्जेक्ट आवंटक को छोड़ देता है, और इसलिए स्तरों के माध्यम से; यह 0 स्तर पर टक्कर मार सकता है, लेकिन आमतौर पर यह नहीं करता है।

नई सरणी को कितनी अतिरिक्त जगह आवंटित की जाती है, जिसमें अब पुरानी सूची और संलग्न वस्तु है?

यह list_resize में संभाला जाता है, और यह दिलचस्प हिस्सा है।

list.append वर्गवार होने से बचने का एकमात्र तरीका ज्यामितीय रूप से आवंटित करना है। पहले कुछ विस्तारों के लिए एक कारक (जैसे 1.2) कचरे के रास्ते से बहुत कम समय तक ओवरलैकोटिंग; बहुत बड़े कारकों (1.6 की तरह) कचरे का बहुत बड़ा उपयोग बहुत बड़े सरणी के लिए बहुत अधिक जगह का उपयोग कर। पाइथन इसे अनुक्रम का उपयोग करके संभालता है जो 2.0 पर शुरू होता है लेकिन जल्दी से 1.25 के आसपास कहीं भी परिवर्तित हो जाता है।

विकास पैटर्न है:: 0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ...


आप 3.3 स्रोत के अनुसार विशेष रूप से sorted के बारे में नहीं पूछा, लेकिन मुझे पता है कि यही आपको प्रेरित करता है।

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

+0

कुडोस। दूसरों के लाभ के लिए जो आश्चर्यचकित हो सकते हैं, अबाउटर्ट [इस पोस्ट] पर चर्चा का जिक्र कर रहा है (http: // stackoverflow।कॉम/ए/18520 9 82/198633) – inspectorG4dget

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