स्टार्टअप पर स्मृति का एक बड़ा हिस्सा आवंटित करना और मुक्त करना "स्मृति को साफ करना?"


18

पुस्तक गेम कोडिंग कम्प्लीट, फोर्थ एडिशन , अध्याय 5 ( गेम इनिशियलाइज़ेशन एंड शटडाउन ), सेक्शन चेकिंग मेमोरी में यह दिलचस्प कोड शामिल है:

bool CheckMemory(const DWORDLONG physicalRAMNeeded, const DWORDLONG virtualRAMNeeded)
{
    MEMORYSTATUSEX status; 
    GlobalMemoryStatusEx(&status);
    if (status.ullTotalPhys < physicalRAMNeeded) 
    {
        // you don’t have enough physical memory. Tell the player to go get a 
        // real computer and give this one to his mother. 
        GCC_ERROR("CheckMemory Failure: Not enough physical memory."); 
        return false;
    }
    // Check for enough free memory.
    if (status.ullAvailVirtual < virtualRAMNeeded) 
    {
        // you don’t have enough virtual memory available.
        // Tell the player to shut down the copy of Visual Studio running in the 
        // background, or whatever seems to be sucking the memory dry. 
        GCC_ERROR("CheckMemory Failure: Not enough virtual memory.");
        return false;
    }

    char *buff = GCC_NEW char[virtualRAMNeeded]; 
    if (buff)
    {
        delete[] buff;
    }
    else
    {
        // even though there is enough memory, it isn't available in one
        // block, which can be critical for games that manage their own memory 
        GCC_ERROR("CheckMemory Failure: Not enough contiguous memory."); 
        return false;
    }
}

इससे कुछ सवाल खड़े होते हैं।

पहला भाग बस ओएस (विंडोज) से पूछता है कि कितनी रैम उपलब्ध है। जिज्ञासु हिस्सा दूसरा है, जो स्मृति का एक बड़ा हिस्सा आवंटित करता है और इसे तुरंत मुक्त करता है:

char *buff = GCC_NEW char[virtualRAMNeeded]; 
if (buff)
{
    delete[] buff;
}

लेखक ने समझाया:

... यह फ़ंक्शन आवंटित करता है और तुरंत मेमोरी का एक बड़ा ब्लॉक जारी करता है। यह विंडोज को किसी भी कचरे को साफ करने का प्रभाव है जो मेमोरी मैनेजर में जमा हो गया है और दो-चेक करता है कि आप एक बड़े पैमाने पर ब्लॉक को आवंटित कर सकते हैं जितनी आपको ज़रूरत है। यदि कॉल सफल होता है, तो आप अनिवार्य रूप से अपने सिस्टम की मेमोरी के माध्यम से एक ज़म्बोनी मशीन के बराबर चलाते हैं, यह आपके गेम के लिए बर्फ को हिट करने के लिए तैयार हो रहा है ...

लेकिन उस पर मेरा आरक्षण है।

"सफाई कचरा जो स्मृति प्रबंधक में जमा हो गया है?" वास्तव में? यदि खेल अभी शुरू हुआ है, तो क्या कोई कचरा नहीं होना चाहिए?

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

इसके अलावा, ओएस को उस सभी मेमोरी को करने के लिए मजबूर करने की संभावना नहीं है, और परिणाम के रूप में स्वैप डिस्क स्थान पर बहुत सारी मेमोरी का अनुमान लगाया जाता है, जिससे आपके ऐप स्टार्टअप बहुत धीमा हो जाता है?

क्या यह वास्तव में एक अच्छा अभ्यास है?


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

क्या जंगल में जमीन की एक लंबी पट्टी को साफ़ करना, एक रेडियो, हेडफ़ोन इत्यादि पर नक्काशी करना, हवाई जहाज से लकड़ी के परिणामस्वरूप उतरना और आपूर्ति करना है?
डैन नीली

10
गेम कोडिंग कम्प्लीट में बहुत सारी बकवास-जोड़ी होती है, न कि बहुत-सी समझ के साथ-सी ++ और सी-कि-सी-सी-सी-सी-सी-सी ++ (इस नमूने में भी दिखाया गया है, जिसके परिणाम की जांच कर operator newरहा है nullptr), अगर आप मुझे अनुमति देते हैं कहना। सबसे अच्छी बात यह है कि आप इस पुस्तक के साथ अपनी चिमनी को हल्का कर सकते हैं। स्मृति के एक बड़े ब्लॉक को आवंटित और मुक्त करना स्मृति को "साफ" नहीं करता है
डेमन

@ डैमन, मैंने जांच नहीं की, लेकिन मुझे संदेह है कि उन्होंने कम से कम वैश्विक newऑपरेटर को फेंकने के बजाय अशक्त लौटने के लिए अधिभारित किया है bad_alloc। यदि वे नहीं करते हैं, तो हाँ, यह कोड और भी अधिक निरर्थक है: P
glampert

1
@glampert: यह मानते हुए भी कि मामला operator deleteस्वीकार करने nullptrऔर इसे नो-ऑप के रूप में मानने के लिए आवश्यक है । कोई भी वैश्विक अधिभार जो ऐसा नहीं करता है वह टूट गया है। इसका मतलब है कि यह किसी भी तरह से निरर्थक है। जैसे मान लेना कि स्मृति का एक बड़ा ब्लॉक आवंटित करना और इसे जारी करना "जादुई रूप से" कुछ अच्छा करेगा। सबसे अच्छा, यह कोई नुकसान नहीं करेगा (सबसे अधिक संभावना है, क्योंकि पृष्ठों को भी नहीं छुआ गया है ... अन्यथा यह आपके कामकाजी सेट से कुछ पृष्ठों को स्वैप कर सकता है जिन्हें आपको बाद में पुनः लोड करना होगा)।
डेमोन

जवाबों:


12

एक बात है कि स्मृति की एक बड़ी हिस्सा पूर्व आवंटन सकता है करते हैं, अगर आपके कंप्यूटर रैम पर कम था, डिस्क के लिए अन्य कार्यक्रमों 'स्मृति स्थान के कुछ हिस्सों को स्वैप करके कुछ अतिरिक्त स्थान खाली करने के ओएस के लिए मजबूर करने हो सकता है।

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

उस ने कहा, स्वैप-टू-डिस्क को इस तरह मजबूर करना 100% विश्वसनीय नहीं है:

  • कई वर्चुअल मेमोरी कार्यान्वयन पर, केवल मेमोरी आवंटित करना वास्तव में किसी भी स्वैपिंग को ट्रिगर नहीं करता है; बल्कि, यह केवल तब होता है जब आप पहली बार आपके द्वारा आवंटित मेमोरी के प्रत्येक पृष्ठ तक पहुंचते हैं। (यह निश्चित रूप से लिनक्स के आधुनिक संस्करणों पर सच है, मेमोरी ओवरकमिट सक्षम है, क्योंकि यह डिफ़ॉल्ट रूप से है; मुझे नहीं पता कि विंडोज के विभिन्न संस्करण इसे कैसे संभालते हैं।)

    इस प्रकार, यदि आप वास्तव में इस कोड को "मेमोरी को साफ़ करना" चाहते हैं, तो आपको संभवतः इसे जारी memset()करने से पहले सरणी के हर हिस्से (या कम से कम पहले physicalRAMNeededबाइट्स) पर डेटा लिखने के लिए एक कॉल या समकक्ष जोड़ना चाहिए ।

  • इसके अलावा, इस तरह रैम से बाहर स्वैप अन्य कार्यक्रमों के लिए ओएस के लिए मजबूर मतलब यह नहीं है कि वे करेंगे रहने इसे से बाहर। विंडोज एक मल्टीटास्किंग ओएस है, और जैसे ही उन स्वैप किए गए कार्यक्रमों में से एक फिर से चलना चाहता है और अपने स्वैप किए गए डेटा का उपयोग करना चाहता है, तो यह वापस स्वैप हो जाएगा, संभवतः आपके गेम को फिर से ठंड कर देगा।

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

    (वहाँ रहे हैं एक कार्यक्रम के लिए तरीके वास्तव में राम में अपनी स्मृति स्थान का एक हिस्सा लॉक करने के लिए ओएस बताने और इसे बाहर बदली होने से रोकने, लेकिन इन आम तौर पर ऊपर उठाया विशेषाधिकारों की आवश्यकता है। किसी भी मामले में, कोड तुम्हें तैनात होने के लिए प्रकट नहीं होता है ऐसी किसी भी विधि का उपयोग करना।)

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


1
निम्न स्तर के स्मृति प्रबंधन के अपने सीमित ज्ञान से, मैं कह सकता हूं कि किसी विशिष्ट पृष्ठ को स्वैप करने या न करने का निर्णय बहुत अधिक जटिल है, और केवल स्मृति की मात्रा और उपलब्ध स्मृति की मात्रा की तुलना में कई और कारकों को ध्यान में रखता है। । इसे ओवरलीप्लाइज़ करना, और आम तौर पर दमन पर भरोसा करना बहुत बुद्धिमानी नहीं है।
पांडा पायजामा

3
मुझे लगता है कि यह याद रखना महत्वपूर्ण है कि ये सभी कार्य हैं जो काम कर सकते हैं, काम नहीं करते हैं, या काम करने लगते हैं, लेकिन पूरी तरह से असंबंधित कारणों से। जहाँ तक मुझे पता है, इस उत्तर में बताए गए किसी भी व्यवहार को प्रलेखित नहीं किया गया है, और उन पर भरोसा करना नासमझी होगी। एक OS अपडेट, सेटिंग्स में बदलाव, संकलक परिवर्तन, या बहुत कुछ भी इस काम को रोक सकता है, या यहां तक ​​कि प्रदर्शन पर नकारात्मक प्रभाव डाल सकता है।
पांडा पायजामा

26

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

सबसे पहले, याद रखें कि प्रत्येक प्रक्रिया के लिए पता स्थान वर्चुअलाइज्ड है। जहाँ तक आपकी प्रक्रिया का संबंध है, आपके पास पूरा पता स्थान स्वयं का है, और आपको हमेशा सन्निहित (आभासी) मेमोरी मिलेगी, चाहे वह स्मृति शारीरिक रूप से सन्निहित हो या नहीं।

वास्तव में, स्मृति भौतिक स्मृति में सन्निहित है या नहीं, कुछ ऐसा नहीं है जिस पर आपका नियंत्रण है। ओएस यह चुनेगा कि भौतिक ब्लॉकों को कैसे आवंटित किया जाए क्योंकि यह फिट दिखता है, और आपके द्वारा आवेदन स्तर पर कुछ भी नहीं करने पर सन्निहित भौतिक स्मृति के लाभों (यदि कोई हो) पर प्रभाव पड़ सकता है।

वर्चुअल मेमोरी फ़्रेग्मेंटेशन के बारे में आपको ध्यान रखने की ज़रूरत है यदि आप बहुत लंबे समय तक विभिन्न आकारों की मेमोरी को आवंटित और मुक्त करते रहें। यह 64-बिट एड्रेस स्पेस के साथ निश्चित रूप से बहुत कम प्रासंगिक है। जब तक हम लंबे समय तक चलने वाले खेल सर्वर के बारे में बात नहीं कर रहे हैं, तब तक खेल आमतौर पर महीनों तक नहीं चलते हैं, इसलिए आपको इस बारे में परवाह नहीं करनी चाहिए।

यहां तक ​​कि अगर आप 32-बिट मशीन में बेतहाशा अलग-अलग आकारों की बहुत सारी मेमोरी आवंटित करते हैं, तो आधुनिक मेमोरी आवंटन बहुत अच्छे हैं, इसलिए यह संभव नहीं है कि आपको वर्चुअल मेमोरी फ़्रेग्मेंटेशन समस्याएँ मिलेंगी जब तक कि आप सक्रिय रूप से उनकी तलाश में न हों

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

मुझे लगता है कि यह एक मामला है "यह किसी कारण के लिए काम करता है जो मुझे वास्तव में समझ में नहीं आता है, इसलिए मैंने इसे समझाने के लिए कुछ बनाया है"।


10
RAM एक घूमने वाली हार्ड डिस्क की तरह नहीं है जहाँ सन्निहित ब्लॉक किसी भी तरह से "बेहतर" नहीं हैं। यह सच नहीं है। सन्निहित रैम एक्सेस यादृच्छिक परिमाण की तुलना में तेजी से परिमाण का एक क्रम है। रैम चिप्स उन खंडों में टूट जाते हैं जिनके लिए स्विच करने के लिए एक निश्चित मात्रा में विलंबता होती है, और इससे भी महत्वपूर्ण बात यह है कि आपकी मेमोरी के बिखरने पर L1 और L2 कैश मिस आपके प्रदर्शन को काफी प्रभावित करेंगे।
कैप्टनकोडरमैन

@CaptainCodeman: मुझे यह स्वीकार करना होगा कि मेरे ज्ञान के क्षेत्र से बाहर चला जाता है, लेकिन किसी भी तरह से, एक Windows -application- प्रोग्रामर के रूप में आप पर कोई नियंत्रण नहीं है कि आपकी स्मृति शारीरिक रूप से सन्निहित है या नहीं। स्मृति के एक विशाल ब्लॉक के लिए पूछने से बहुत कुछ नहीं बदलेगा।
पांडा पाजामा

@CaptainCodeman वास्तव में सन्निहित आभासी ब्लॉक में सन्निहित आधुनिक 2 में है ^ रैम में एन ब्लॉक कैश लाइन आवंटन के कारण इसे गति देगा
शाफ़्ट सनकी

8
@CaptainCodeman हाँ, अनुक्रमिक DRAM पहुँच तेज़ है, लेकिन हम वर्चुअल-> भौतिक मानचित्रण के बारे में बात कर रहे हैं जो 4 KB (या अधिक) के पन्नों में होता है, इसलिए कि क्या मैपिंग अनुक्रमिक है या नहीं, इसका मेमोरी पर बहुत अधिक प्रभाव नहीं होना चाहिए गति पढ़ें। इसके अलावा, कैश प्रीफ़ेचिंग और सामान जैसे कि वर्चुअल एड्रेस स्पेस में संचालित होता है, भौतिक नहीं।
नाथन रीड

1
@NathanReed मेला पर्याप्त है, और स्पष्टीकरण के लिए धन्यवाद। मैं सिर्फ यह व्यक्त कर रहा था कि रैम एक्सेस की गति मेमोरी स्पेस में पूरी तरह से समान नहीं है, जैसा कि सुझाव दिया गया था।
कैप्टनकोडरमैन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.