2010-06-16 10 views
7

मैं सी # और एक्सएनए से शुरू कर रहा हूं। "गेम" कक्षा के "अपडेट" विधि में मेरे पास यह कोड है:सी #/एक्सएनए - स्मृति को स्मृति लोड करें - यह कैसे काम करता है?

t = Texture2D.FromFile([...]); //t is a 'Texture2D t;' 

जो छोटी छवि लोड करता है। "अपडेट" विधि लूप की तरह काम कर रही है, इसलिए इस कोड को दूसरी बार कई बार कहा जाता है। अब, जब मैं अपना गेम चलाता हूं, तो इसमें 9 5 एमबी रैम लगता है और यह लगभग 130 एमबी तक चला जाता है (कोड के कारण मैंने पोस्ट किया है, इस कोड के बिना यह 95 एमबी पर रहता है), फिर तुरंत 100 एमबी (कचरा कॉललेशन) तक चला जाता है? और फिर धीरे-धीरे 130 एमबी तक चला जाता है, फिर तुरंत 100 एमबी तक और इसी तरह। तो मेरा पहला सवाल:

  1. क्या आप समझा सकते हैं कि यह क्यों (कैसे) ऐसा काम करता है?

मैं, पाया है कि मैं करने के लिए कोड बदलने यदि:

t.Dispose() 
t = Texture2D.FromFile([...]); 

यह है कि तरह काम करता है: पहला यह 95MB लेता है और फिर धीरे धीरे ( कोड के कारण) 101MB के बारे में करने के लिए चला जाता है और इस स्तर पर बनी हुई है।

  1. मुझे समझ में नहीं आता कि यह 6 एमबी (101-95) क्यों लेता है ...?

  2. मैं इसे इस तरह काम करना चाहता हूं: लोड छवि, स्मृति से रिलीज, लोड छवि, स्मृति से मुक्त होना आदि, इसलिए प्रोग्राम को हमेशा 95 एमबी लेना चाहिए (जब यह छवि केवल पिछले एक बार लोड हो जाती है तो यह 9 5 एमबी लेता है तरीका)। मुझे किस निर्देश का उपयोग करना चाहिए?

यदि यह महत्वपूर्ण है, तो छवि का आकार लगभग 10 केबी है।

धन्यवाद!

उत्तर

3

अद्यतन विधि, क्योंकि यह एक बहुत भरी हुई है बनावट लोड करने के लिए नहीं किया जाना चाहिए। .NET में, ऑब्जेक्ट्स कचरा एकत्रित होते हैं, जिसका अर्थ है कि आप किसी ऑब्जेक्ट को स्पष्ट रूप से मुक्त नहीं कर सकते हैं (यहां तक ​​कि डिस्प्ले ऐसा नहीं करता है)।

प्रणाली बहुत दबाव के अधीन है, जी सी के रूप में अक्सर ऐसा कर सकता है के रूप में नहीं चला सकते हैं।

संक्षेप में: आप हजारों बनावट 2 डी "लीक" कर रहे हैं।

लोड उन्हें प्रारंभ घटनाक्रम में से एक में है और उन्हें एक वर्ग चर, शब्दकोश, सूची या जो कुछ भी संरचना में स्टोर करने के लिए उचित तरीके से। असल में, इसे केवल एक बार लोड करें और फिर इसका पुन: उपयोग करें।

आप ऑन-डिमांड एक बनावट लोड करने के लिए है, तो केवल एक बार लोड और सूची/शब्दकोश/क्लास चर में संग्रहीत और इसे फिर से पुन: उपयोग।

संपादित करें: "लोड छवि, रिलीज, लोड, रिलीज" .net में काम नहीं करेगा, बस क्योंकि आप स्पष्ट रूप से मुक्त नहीं कर सकते हैं स्मृति का आपका दृष्टिकोण। आप जीसी को कॉल कर सकते हैं। चयन करें, लेकिन वह ए) इसे गारेट नहीं करता है और बी) जीसी। चयन अविश्वसनीय रूप से धीमा है।

वहाँ कारण है कि आप छवि 60 बार एक दूसरे को फिर से लोड करने के लिए है एक विशेष कारण है? यदि आपको केवल हर सेकेंड या फिर इसे पुनः लोड करने की आवश्यकता है, तो आप अंतिम के बाद समाप्त होने वाले समय को मापने के लिए elapsedGameTime का उपयोग कर सकते हैं। अद्यतन करें और यदि यह आपकी दहलीज से अधिक है, तो छवि को दोबारा लोड करें।(आपको "LastUpdated" जैसे क्लास वैरिएबल की आवश्यकता है जिसके विरुद्ध आप तुलना करते हैं और जब आप छवि को फिर से लोड करते हैं तो आप अपडेट करते हैं)

13

सबसे पहले आपको यह समझने की आवश्यकता है कि आप जो कर रहे हैं वह बहुत अजीब है!

एक बनावट लोड करने का "सामान्य" तरीका सामग्री पाइपलाइन और सामग्री प्रबंधक का उपयोग करना है।

यदि आपको वास्तव में फ़ाइल से बनावट लोड करना है, न कि सामग्री प्रणाली - आपको प्रत्येक बनावट के लिए केवल एक बार ऐसा करना चाहिए। आपको Texture2D.FromFileGame.LoadContent में Dispose पर कॉल करना चाहिए और Game.UnloadContent में सामान्य रूप से सामग्री प्रबंधक कॉल करना होगा - लेकिन क्योंकि आप सामग्री प्रबंधक से नहीं जा रहे हैं, आपको कॉल करना होगा स्वयं को निपटाना)।


महत्वपूर्ण बात यह एहसास है कि तुम दोनों में कामयाब रहे और अप्रबंधित संसाधनों यहाँ के साथ काम कर रहे हैं।

स्मृति प्रबंधित वस्तुओं द्वारा किया जा रहा कचरा कलेक्टर द्वारा नियंत्रित किया जाएगा - इस मामले में Texture2D के प्रत्येक उदाहरण के एक छोटे कामयाब स्मृति के बिट का उपयोग करता है। 99% बार आपको इसके बारे में चिंता करने की आवश्यकता नहीं है - कचरा कलेक्टर प्रबंधित स्मृति को संभालने में वाकई अच्छा है - यह उसका काम है!

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

लेकिन कचरा कलेक्टर इन सभी Textman2D ऑब्जेक्ट्स का उपयोग कर रहे सभी अप्रबंधित संसाधनों को "देख" नहीं सकता है। यह नहीं पता कि उन वस्तुओं को कब जारी किया जाना चाहिए - आप स्वयं को बेहतर काम कर सकते हैं। आपको बस अपने बनावट पर Dispose पर कॉल करना है जब उन्हें अब आवश्यकता नहीं है।

यह क्योंकि कचरा कलेक्टर अपनी संरचनाओं द्वारा प्रयोग किया जाता अतिरिक्त स्मृति की कि 30MB के बारे में पता नहीं है कि यह संचित किया जा रहा है आप निपटान बुला नहीं कर रहे हैं जब है,। इसके अतिरिक्त, जब आप प्रक्रिया मेमोरी उपयोग को देखते हैं तो आप क्या नहीं देख सकते हैं, GPU पर सभी मेमोरी है कि वे बनावट उपयोग कर रहे हैं!

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


- - एक Texture2D वस्तु का केवल लगभग 100-200 बाइट है। के लिए के रूप में आप क्या हासिल करने की कोशिश कर रहे हैं । आप वास्तव में एक बनावट हर फ्रेम लोड करने के लिए (इस अत्यधिक असामान्य है), और आप फिर भी नहीं रह गया है पिछले बनावट की जरूरत है एक की जरूरत ...

ठीक है, सब से पहले, पर Dispose बुला है, तो अप्रयुक्त बनावट प्रत्येक फ्रेम एक मान्य विधि है। आप कचरा कलेक्टर सब कचरा इस बनाता है (Texture2D वस्तुओं की कामयाब पक्ष) को साफ करने के आधार पर किया जाएगा - यह विंडोज पर ठीक है पर Xbox पर अपने प्रदर्शन को मारने सकता है। कम से कम आप अप्रबंधित संसाधनों को लीक नहीं करेंगे।

एक बेहतर तरीका, विशेष रूप से यदि बनावट हर बार एक ही आकार है, तो केवल उसी बनावट वस्तु का उपयोग करना जारी रखना है। फिर प्रत्येक फ्रेम के नए बनावट डेटा के साथ Texture2D.SetData पर कॉल करें।

(अपनी संरचनाओं विभिन्न आकारों हैं, या आप एक निश्चित समय पर उपयोग में एक से अधिक है, तो आप एक बनावट पूल की तरह कुछ को लागू करने की आवश्यकता हो सकती है।)

बेशक

, LoadFile एक वास्तविक फ़ाइल लेता है, सेटडाटा कच्चा डेटा लेता है। आपको डेटा रूपांतरण स्वयं लागू करना होगा। एक अच्छा प्रारंभिक बिंदु this thread on the XNA forum हो सकता है।

0

जैसा कि एंड्रयू रसेल कहते हैं, प्रति सेकंड 60 बार अपनी छवि लोड करना वह नहीं है जो आप करना चाहते हैं। हालांकि, मैं जोड़ूंगा: Texture2D.FromFile का उपयोग न करें!

एक्सएनए आपके लिए एक मजबूत सामग्री पाइपलाइन प्रदान करता है - इसका उपयोग करें!

  1. अपने खेल परियोजना के लिए अपनी छवि को जोड़ें। डिफ़ॉल्ट रूप से एक्सएनए जानता है कि पीएनजी, जीआईएफ, और जेपी (ई) जी छवि प्रकारों के साथ क्या करना है। जब आप अपनी परियोजना को संकलित करते हैं, तो एक्सएनए आपकी छवि को एक्सएनए बाइनरी (* .XNB) फ़ाइल प्रारूप में भी संसाधित करेगा।
  2. MyGame.LoadContent में, myTexture = Content.Load<Texture2D>(@"My/Image/Folder/MyImageAssetName")

Content.Load का उपयोग कर अपनी छवि के संकलित XNB संस्करण लोड होगा अपनी छवि को लोड करते हैं। आप अपनी प्रोजेक्ट में छवि गुणों में चीजें भी कर सकते हैं जैसे मास्किंग रंग सेट करें (उदा: आपके जेपीजी में सभी सफेद पिक्सेल आपके गेम में पारदर्शी होंगे), छवि को स्केल करें और संपत्ति का नाम बदलें। (परिसंपत्ति नाम छवि फ़ाइल नाम के लिए चूक, लेकिन आप संपत्तियों में इसे बदल सकते हैं, और परिसंपत्ति नाम आप Content.Load के लिए क्या प्रयोग करेंगे।)

Content.Load भी बातें लोड कैश, ताकि के लिए करता है, तो कुछ कारणों से आपको एक ही संपत्ति पर कई बार Load पर कॉल करना होगा, आप जिस स्मृति का उपयोग करते हैं उसे गुणा नहीं कर रहे हैं।

एक्सएनए सामग्री पाइपलाइन का उपयोग कई अन्य चीजों के साथ-साथ 3 डी मॉडल, ध्वनि और यहां तक ​​कि अपनी खुद की कक्षाओं सहित छवियों के लिए भी किया जा सकता है।

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