android - बिटमैप फैक्टरी ओओएम मुझे पागल गाड़ी चला रहा है




out-of-memory (4)

मैं बहुत सारी खोज कर रहा हूं और मुझे पता है कि कई अन्य लोग BitmapFactory साथ एक ही BitmapFactory मेमोरी समस्याओं का सामना कर रहे हैं। मेरा ऐप केवल Runtime.getRuntime ().totalMemory() का उपयोग करके 4 एमबी की कुल मेमोरी उपलब्ध कराता है। यदि सीमा 16 एमबी है, तो बिटमैप के लिए जगह बनाने के लिए कुल मेमोरी क्यों नहीं बढ़ती है? इसके बजाय यह एक त्रुटि फेंकता है।

मुझे यह भी समझ में नहीं आता कि अगर मेरे पास Runtime.getRuntime().freeMemory() की मुफ्त मेमोरी है। मुफ्त मेमरी Runtime.getRuntime().freeMemory() मुझे यह क्यों त्रुटि मिलती है कि "वीएम हमें 614400 बाइट आवंटित नहीं करेगा"? मुझे लगता है कि मेरे पास पर्याप्त उपलब्ध स्मृति है।

मेरा ऐप इस समस्या को छोड़कर पूरा हो गया है, जो फोन को रीबूट करते समय चला जाता है ताकि मेरा ऐप एकमात्र चीज चल रहा हो। मैं डिवाइस परीक्षण (एंड्रॉइड 1.5) के लिए एक एचटीसी हीरो का उपयोग कर रहा हूं।

इस बिंदु पर मैं सोच रहा हूं कि इसके आसपास एकमात्र तरीका BitmapFactory का उपयोग करने से BitmapFactory

किसी के पास इस पर कोई विचार है या एक स्पष्टीकरण है कि 1.6 एमबी मुक्त मेमोरी होने पर वीएम 614 केबी आवंटित क्यों नहीं करेगा?


1.6 एमबी मेमोरी बहुत कुछ लगता है लेकिन यह मामला हो सकता है कि स्मृति इतनी बुरी तरह विभाजित है कि यह एक बार में स्मृति के इतने बड़े ब्लॉक को आवंटित नहीं कर सकता है (फिर भी यह बहुत अजीब लगता है)।

छवि संसाधनों का उपयोग करते समय ओओएम का एक आम कारण यह है कि जब कोई वास्तव में उच्च संकल्प वाले जेपीजी, पीएनजी, जीआईएफ छवियों को डिकंप्रेस कर रहा है। आपको यह ध्यान में रखना होगा कि ये सभी प्रारूप बहुत अच्छी तरह से संपीड़ित हैं और बहुत कम जगह लेते हैं लेकिन एक बार जब आप फोन पर छवियों को लोड करते हैं, तो वे जिस स्मृति का उपयोग करने जा रहे हैं वह width * height * 4 bytes । साथ ही, जब डिकंप्रेशन में प्रवेश होता है, तो कुछ अन्य सहायक डेटा संरचनाओं को डीकोडिंग चरण के लिए लोड करने की आवश्यकता होती है।


[ध्यान दें कि (जैसा कि कॉमन्सवेयर नीचे बताए गए हैं) इस उत्तर में पूरा दृष्टिकोण केवल 2.3.x (जिंजरब्रेड) तक लागू होता है। हनीकॉम बिटमैप डेटा के रूप में वीएम ढेर में आवंटित किया जाता है।]

वीएम ढेर में बिटमैप डेटा आवंटित नहीं किया गया है। वीएम हीप (जो छोटा है) में इसका एक संदर्भ है, लेकिन अंतर्निहित स्कीया ग्राफिक्स लाइब्रेरी द्वारा मूल ढेर में वास्तविक डेटा आवंटित किया जाता है।

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

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

देशी ढेर के आकार की निगरानी करने के लिए दिनचर्या हैं (डीबग क्लास प्राप्त करने के तरीके को देखें)। हालांकि, मुझे पता चला है कि GetHativeHeapFreeSize () और getNativeHeapSize () विश्वसनीय नहीं हैं। तो मेरे अनुप्रयोगों में से एक जो गतिशील रूप से बड़ी संख्या में बिटमैप्स बनाता है, मैं निम्न कार्य करता हूं।

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

long mMaxVmHeap     = Runtime.getRuntime().maxMemory()/1024;
long mMaxNativeHeap = 16*1024;
if (mMaxVmHeap == 16*1024)
     mMaxNativeHeap = 16*1024;
else if (mMaxVmHeap == 24*1024)
     mMaxNativeHeap = 24*1024;
else
    Log.w(TAG, "Unrecognized VM heap size = " + mMaxVmHeap);

फिर हर बार हमें बिटमैप फैक्ट्री को कॉल करने की आवश्यकता होती है, हम फॉर्म के चेक द्वारा कॉल से पहले जाते हैं।

long sizeReqd        = bitmapWidth * bitmapHeight * targetBpp  / 8;
long allocNativeHeap = Debug.getNativeHeapAllocatedSize();
if ((sizeReqd + allocNativeHeap + heapPad) >= mMaxNativeHeap)
{
    // Do not call BitmapFactory…
}

ध्यान दें कि हेपपैड एक जादू संख्या है जो इस तथ्य की अनुमति देने के लिए है कि ए) मूल ढेर आकार की रिपोर्टिंग "मुलायम" है और बी) हम अन्य अनुप्रयोगों के लिए मूल ढेर में कुछ जगह छोड़ना चाहते हैं। हम वर्तमान में 3 * 1024 * 1024 (यानी 3 एमबाइट्स) पैड के साथ चल रहे हैं।


यद्यपि आमतौर पर यह त्रुटि को पकड़ने के लिए समझ में नहीं आता है क्योंकि आमतौर पर उन्हें केवल वीएम द्वारा फेंक दिया जाता है लेकिन इस विशेष मामले में त्रुटि जेनी गोंद कोड द्वारा फेंक दी जाती है, इस प्रकार उन मामलों को संभालना बहुत आसान होता है जहां आप छवि लोड नहीं कर सकते: बस OutOfMemoryError पकड़ो।


यद्यपि यह काफी उच्च स्तर का उत्तर है, लेकिन मेरे लिए समस्या मेरे सभी विचारों पर हार्डवेयर त्वरण का उपयोग करने के लिए बाहर निकली। मेरे अधिकांश विचारों में कस्टम बिटमैप मैनिपुलेशन है, जिसे मैंने बड़े देशी ढेर आकार का स्रोत माना, लेकिन वास्तव में जब हार्डवेयर त्वरण को अक्षम किया गया तो देशी ढेर का उपयोग 4 के कारक द्वारा घटा दिया गया।

ऐसा लगता है कि हार्डवेयर त्वरण आपके विचारों पर सभी प्रकार के कैशिंग करेगा, स्वयं के बिटमैप्स बनायेगा, और चूंकि सभी बिटमैप मूल ढेर साझा करते हैं, आवंटन आकार बहुत नाटकीय रूप से बढ़ सकता है।





out-of-memory