आप स्मृति स्थितियों से बाहर निकलने की तैयारी कैसे करते हैं?


18

यह अच्छी तरह से परिभाषित दायरे वाले खेलों के लिए आसान हो सकता है, लेकिन सवाल सैंडबॉक्स गेम के बारे में है, जहां खिलाड़ी को कुछ भी बनाने और बनाने की अनुमति है ।

संभव तकनीक:

  • ऊपरी सीमा के साथ मेमोरी पूल का उपयोग करें।
  • उन वस्तुओं को हटा दें जिनकी अब समय-समय पर आवश्यकता नहीं है।
  • शुरुआत में अतिरिक्त मात्रा में मेमोरी आवंटित करें ताकि इसे बाद में पुनर्प्राप्ति तंत्र के रूप में मुक्त किया जा सके। मैं लगभग 2-4 एमबी कहूंगा।

यह मोबाइल / कंसोल प्लेटफार्मों में होने की अधिक संभावना है जहां मेमोरी आमतौर पर आपके 16 जीबी पीसी के विपरीत सीमित होती है। मैं मान रहा हूं कि आपके पास मेमोरी आवंटन / डीलक्लोलेशन पर पूर्ण नियंत्रण है और इसमें कोई कचरा संग्रह शामिल नहीं है। इसलिए मैं इसे C ++ के रूप में टैग कर रहा हूं।

कृपया ध्यान दें कि मैं प्रभावी C ++ आइटम 7 के बारे में बात नहीं कर रहा हूं "" आउट-ऑफ-मेमोरी शर्तों के लिए तैयार रहें " , हालांकि यह प्रासंगिक है, मैं खेल विकास से संबंधित एक उत्तर को अधिक देखना चाहता हूं, जहां आमतौर पर आपके पास अधिक नियंत्रण होता है। हो रहा।

प्रश्न को संक्षेप में बताने के लिए, आप सैंडबॉक्स गेम के लिए मेमोरी की स्थिति से बाहर कैसे तैयार होते हैं, जब आप एक प्लेटफॉर्म को सीमित मेमोरी कंसोल या मोबाइल के साथ लक्षित कर रहे हैं?


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

@ खिल्ली हाँ मुझे पता है। लेकिन मेरा सवाल स्मृति सीमित उपकरणों जैसे कंसोल और मोबाइल के प्रति अधिक है जो मुझे लगता है कि मैंने उल्लेख किया है।
concept3d 14

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

@ बाइट 56 मैंने प्रश्न संपादित किया। मुझे उम्मीद है कि अब इसमें अधिक परिभाषित गुंजाइश है।
कॉन्सेप्ट

जवाबों:


16

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

जब आपके पास एक ऊपरी मेमोरी कैप होती है, तो आप केवल यह सुनिश्चित करते हैं कि आपको उस मेमोरी से अधिक की आवश्यकता नहीं है। उदाहरण के लिए, आप एक समय में अधिकतम अनुमत NPCs रख सकते हैं, और उस टोपी के हिट होते ही नए गैर-आवश्यक NPCs को बंद करना बंद कर दें। आवश्यक NPCs के लिए आप या तो उन्हें गैर-आवश्यक लोगों को बदल सकते हैं या आवश्यक NPCs के लिए एक अलग पूल / कैप रख सकते हैं, जो आपके डिज़ाइनर्स को डिज़ाइन करना जानते हैं (जैसे कि यदि आपके पास केवल 3 आवश्यक NPCsa हो सकते हैं, तो डिज़ाइनर 3 से अधिक नहीं डालेंगे। एक क्षेत्र / चंक - अच्छे उपकरण डिजाइनरों को इसे ठीक से करने में मदद करेंगे और परीक्षण आवश्यक है)।

विशेष रूप से सैंडबॉक्स गेम के लिए एक बहुत अच्छा स्ट्रीमिंग सिस्टम भी महत्वपूर्ण है। आपको सभी NPC और आइटम को मेमोरी में रखने की आवश्यकता नहीं है। जैसा कि आप दुनिया के विखंडू के माध्यम से आगे बढ़ते हैं, नए विखंडू में प्रवाहित होंगे और पुराने विखंडू बाहर प्रवाहित होंगे। इनमें आमतौर पर एनपीसी और आइटम के साथ-साथ इलाके भी शामिल होंगे। आइटम सीमा पर डिजाइन और इंजीनियरिंग कैप को इस प्रणाली को ध्यान में रखते हुए सेट करने की आवश्यकता है, यह जानकर कि अधिकांश एक्स पुराने चनों को चारों ओर रखा जाएगा और प्रो-सक्रिय रूप से लोड किए गए वाई नए चक्कों को लोड किया जाएगा, इसलिए गेम को सभी को रखने के लिए जगह की आवश्यकता है मेमोरी में X + Y + 1 हिस्सा का डेटा।

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

allocate(bytes):
  if can_allocate(bytes):
    return internal_allocate(bytes)
  else:
    warning(LOW_MEMORY)
    tell_systems_to_dump_caches()

    if can_allocate(bytes):
      return internal_allocate(bytes)
    else:
      fatal_error(OUT_OF_MEMORY)

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

उदाहरण के लिए, यदि आप GPU मेमोरी (या साझा मेमोरी आर्किटेक्चर में कोई मेमोरी) पर कम चल रहे हैं, तो आप कुछ डेटा की उच्च-रिज़ॉल्यूशन प्रतियों को डंप करने पर भी विचार कर सकते हैं। यह आमतौर पर इसके लायक बनाने के लिए बहुत सारे वास्तुशिल्प काम की आवश्यकता होती है, हालांकि।

ध्यान दें कि कुछ बहुत ही असीमित सैंडबॉक्स गेम आसानी से बस दुर्घटनाग्रस्त हो सकते हैं, यहां तक ​​कि पीसी पर भी (याद रखें कि आम 32-बिट ऐप्स में 2-3GB पता स्थान की सीमा होती है, भले ही आपके पास 128GB RAM वाला पीसी हो; 64- बिट OS और हार्डवेयर अधिक 32-बिट ऐप्स को एक साथ चलाने की अनुमति देता है लेकिन 32-बिट बाइनरी को बड़ा पता स्थान बनाने के लिए कुछ भी नहीं कर सकता है)। अंत में, आपके पास या तो एक बहुत ही लचीली गेम की दुनिया है जिसे हर मामले में चलने के लिए अनबाइंड मेमोरी स्पेस की आवश्यकता होगी या आपके पास एक बहुत ही सीमित और नियंत्रित दुनिया है जो हमेशा बंधी हुई मेमोरी (या बीच में कहीं कुछ) में पूरी तरह से काम करती है।


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

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

5

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

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

इसके अलावा गेम डिज़ाइन को हमेशा सबसे कम लक्षित उपकरणों को ध्यान में रखना चाहिए क्योंकि यदि आप अपने डिज़ाइन को "असीमित" चीजों के साथ करते हैं तो यह मेमोरी समस्याओं को हल करने या बाद में डिज़ाइन को बदलने के लिए बहुत कठिन होगा।


1

ठीक है, आप स्टार्टअप पर या .bssसंकलन के समय भी लगभग 16 MiB (केवल 100% सुनिश्चित होना) आवंटित कर सकते हैं , और एक "सुरक्षित आवंटनकर्ता" का उपयोग कर सकते हैं, जैसे कि एक हस्ताक्षर है inline __attribute__((force_inline)) void* alloc(size_t size)( __attribute__((force_inline))एक GCC / mingw-w64विशेषता है जो महत्वपूर्ण कोड अनुभागों को सम्मिलित करने के लिए मजबूर करता है। भले ही अनुकूलन को अक्षम कर दिया जाता है, भले ही उन्हें खेलों के लिए सक्षम होना चाहिए) इसके बजाय mallocकोशिश करता है void* result = malloc(size)और अगर यह विफल हो जाता है, तो कैश को छोड़ दें, अतिरिक्त मेमोरी को खाली करें (या अन्य कोड को उपयोग करने के लिए कहें .bssलेकिन यह इस उत्तर के लिए गुंजाइश से बाहर है) और बिना सहेजे गए डेटा को फ्लश करें (डिस्क पर दुनिया को बचाएं, यदि आप किसी Minecraft जैसी अवधारणा का उपयोग करते हैं, तो कुछ कॉल करें saveAllModifiedChunks())। फिर, अगर malloc(16777216)(इन 16 MiB को फिर से आवंटित करना) विफल रहता है (फिर से, एनालॉग के साथ बदलें .bss), खेल और शो को समाप्त करेंMessageBox(NULL, "*game name* couldn't continue because of lack of free memory, but your world was safely saved. Try closing background applications and restarting the game", "*Game name*: out of memory", MB_ICONERROR)या एक मंच विशिष्ट विकल्प। यह सब एक साथ डालें:

__attribute__((force_inline)) void* alloc(size_t size) {
    void* result = malloc(size); // Attempt to allocate normally
    if (!result) { // If the allocation failed...
        if (!reserveMemory) std::_Exit(); // If alloc() was called from forceFullSave() or reportOutOfMemory() and we again can't allocate, just quit, something is stealing all our memory. If we used the .bss approach, this wouldn't've been necessary.
        free(reserveMemory); // Global variable, pointer to the reserve 16 MiB allocated on startup
        forceFullSave(); // Saves the game
        reportOutOfMemory(); // Platform specific error message box code
        std::_Exit(); // Close silently
    } else return result;
}

आप के साथ एक समान समाधान का उपयोग कर सकते हैं std::set_new_handler(myHandler)जहां myHandlerहैvoid myHandler(void) कि जब कहा जाता है newविफल रहता है:

void newerrhandler() {
    if (!reserveMemory) std::_Exit(); // If new was called from forceFullSave() or reportOutOfMemory() and we again can't allocate, just quit, something is stealing all our memory. If we used the .bss approach, this wouldn't've been necessary.
    free(reserveMemory); // Global variable, pointer to the reserve 16 MiB allocated on startup
    forceFullSave(); // Saves the game
    reportOutOfMemory(); // Platform specific error message box code
    std::_Exit(); // Close silently
}

// In main ()...
std::set_new_handler(newerrhandler);
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.