2012-05-21 24 views
19

मैं एंड्रॉइड 3.1, बड़े हेपसाइज विकल्प पर परीक्षण कर रहा हूं, लगभग 250 एम मेमोरी उपलब्ध है। - मैं बटन समस्या के बिना कई बार हिट कर सकते हैंएंड्रॉइड जीसी मेमोरी विखंडन विफल। वैकल्पिक हल?

float [][][]foo = new float[3][2048][2048]; 
Bitmap bm = Bitmap.createBitmap(2048, 2048, Bitmap.Config.ARGB_8888); 
bm.recycle(); 
bm = null; 
foo = null; 

मैं इस के लिए स्मृति के बहुत सारे है:

मैं जब भी मैं मेरे ऐप की वरीयता में टेस्ट बटन हिट चलाने के लिए निम्न कोड निर्धारित किया है।

लेकिन अगर मैं बटन को मारता रहता हूं, अंततः (20 से कम हिट) यह आउटऑफमेमरी के साथ मर जाता है। [आमतौर पर android.graphics.Bitmap.nativeCreate (मूल विधि)]

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

क्या यह विखंडन के कारण है, या एंड्रॉइड बिटमैप कोड और/या जीसी में बस एक भयानक बग है? या मैं बस कुछ बेवकूफ कर रहा हूँ? (कृपया इसे कुछ बेवकूफ बनें ...)

क्या किसी के पास कोई कामकाज है? चूंकि उपर्युक्त प्रत्येक बार उपयोगकर्ता द्वारा इसे आमंत्रित करने के लिए मेरे कोड को क्या करना है, और वास्तव में चर के सावधानीपूर्वक समाशोधन के बावजूद कुछ उपयोगों के बाद मर जाता है। (और यह मुझे पागल एक लंबे समय के लिए अब ड्राइविंग कर दिया गया है!)

[अपडेट]

मैंने पुष्टि की है कि यह एक विखंडन मुद्दे या जीसी बग है, के रूप में एक ढेर डंप मैं केवल 5.6M जब उपयोग कर रहा हूँ पता चलता प्रसंस्करण के दौरान लगभग 26 मीटर पर निष्क्रिय (कोई रिसाव नहीं)। (इसके अलावा, देशी ढेर 4 एम से नीचे रहता है।) जबकि जावा ढेर इस समय मेरे परीक्षण डिवाइस पर 280 एम सीमा तक बढ़ता है, जिस बिंदु पर मैं आउटऑफमेमरी अपवाद प्राप्त करना शुरू करता हूं। तो मैं केवल अपने उपलब्ध ढेर का 10% चोटी पर उपयोग कर रहा हूं, लेकिन आउटऑफमेमरी प्राप्त कर रहा हूं।

[System.gc() को कॉल जोड़ना दुर्भाग्य से ऊपर दिए गए सरल परीक्षण मामले को ठीक करता है। मैं दुर्भाग्यपूर्ण कहता हूं क्योंकि (ए) इसे कोई फर्क नहीं पड़ता है, और (बी) क्योंकि मैं इसे पहले से ही अपने वास्तविक कोड में नियमित रूप से कॉल करता हूं, इसका मतलब है कि ऊपर मेरा सरल परीक्षण मामला बहुत आसान है।]

क्या कोई और चलाता है इस मामले में? कोई कामकाज? क्या मेरे ऐप को पुनरारंभ करने का कोई शानदार तरीका है?

[अपडेट]

निम्न संस्करण मज़बूती से 3 से 4 आमंत्रण (बटन के प्रेस) में OutOfMemory कारण बनता है:

float [][][]foo = new float[3][2048][2048]; 
Bitmap bm = Bitmap.createBitmap(2048, 2048, Bitmap.Config.ARGB_8888); 
int []bar = new int[3*2048*2048]; 
bm.recycle(); 
bm = null; 
System.gc(); 
foo = null; 
System.gc(); 
bar = null; 
System.gc(); 

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

मैं कहूंगा कि यह एक विखंडन मुद्दा है, प्रति जीसी बग नहीं। अगर कोई जानता है कि इसे कैसे ठीक किया जाए, तो मुझे बताएं। Int [] आवंटन बिटमैप लिखने के लिए है, इसलिए मेरे पास 2 डी सरणी (एंड्रॉइड बिटमैप लाइब्रेरी की सीमा) के रूप में आवंटित करने का विकल्प नहीं है।

+0

मुझे नहीं पता कि इससे मदद मिलेगी, लेकिन दल्विक एक [मार्क-एंड-स्वीप] का उपयोग करता है (http://www.brpreiss.com/books/opus5/html/page424.html#SECTION0014300000000000000000) जीसी टाइप करें। जहां तक ​​सभी उपलब्ध स्मृति का उपयोग नहीं किया जाता है, तब इसे प्रतीक्षा करने का प्रयास किया जाएगा, फिर इसे एक बार में साफ़ करें (प्रदर्शन समस्याएं, क्योंकि इसे जीसी में प्रसंस्करण रोकने की आवश्यकता है)। शायद 'System.gc();' कॉल इस समस्या के साथ बिल्कुल जरूरी है, क्योंकि जीसी छोटी वस्तुओं की अपेक्षा कर रहा है। – Ancantus

+1

@Ancantus - दुर्भाग्यवश, जैसा कि बताया गया है, मैं अपने असली कोड में प्रत्येक रीसायकल()/null के बाद System.gc() को कॉल करता हूं और अभी भी यह व्यवहार प्राप्त करता हूं। मुझे लगता है कि यह एक विखंडन समस्या है या System.gc() जैसे कुछ पृष्ठभूमि थ्रेड में अनदेखा या व्यवहार किया जा रहा है। यदि स्मृति करने के लिए एक विश्वसनीय तरीका था तो स्मृति को कॉम्पैक्ट करने के लिए मैं अपने ऐप को स्क्रैच से मारने और पुनरारंभ करने के इच्छुक हूं। मुझे यह बताने के लिए भी एक कॉल करना होगा, जीसी के बाद, जावा ढेर का कितना खाली स्थान है (जो मुझे तुरंत बताएगा और निश्चित रूप से यह एक विखंडन समस्या या अस्पष्ट रिसाव है)। क्या कोई है? – Brandyn

+0

याहू जैसा कि आप शायद 'System.gc() को कॉल करना जानते हैं;' जीसी शुरू करने के लिए सिर्फ झंडे को झुकाता है, इसका मतलब यह नहीं है कि यह बिल्कुल चल जाएगा। असल में मैं जीसी बिटमैप से संबंधित समस्याओं के लिए एक खोज कर रहा था, [यह SO सवाल] (http://stackoverflow.com/questions/7852943/what-does-bitmaprecycle-in-android-honeycomb-actually-do) मदद कर सकता है। – Ancantus

उत्तर

1

विखंडन को रोकने के लिए, आप केवल बड़े सरणी और बिटमैप को आवंटित कर सकते हैं और इसका पुन: उपयोग कर सकते हैं।

एंड्रॉइड के लिए, इसमें कुछ चेतावनी हैं, क्योंकि एंड्रॉइड कुछ हद तक आपके ऐप के संसाधनों को प्रबंधित करने का प्रयास करता है।उदाहरण के लिए, Activity या View को दिखाई देने पर अनलोड किया जा सकता है, और बाद में फिर से दिखाई देने पर फिर से चलाया जा सकता है। इसलिए बड़ी चीजों को Application ऑब्जेक्ट या static स्थान द्वारा बेहतर रूप से संग्रहीत किया जाना चाहिए।

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

+0

दुर्भाग्य से कोई विकल्प नहीं है। यह एक छवि प्रसंस्करण अनुप्रयोग है जो विभिन्न आकारों की उपयोगकर्ता द्वारा आपूर्ति की गई छवियों को लेता है (बिना हार्ड-कैप अधिकतम - अधिकतम जो भी उपलब्ध स्मृति में निचोड़ सकता है) – Brandyn

+0

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

+0

@ ब्रैंडिन 2016 में स्मृति विखंडन के साथ समस्या अभी भी मौजूद है। मैंने लूकाचे का उपयोग शुरू किया लेकिन कुछ जोड़े के बाद उपयोग के महीनों में मुझे लगता है कि यह स्मृति विखंडन के कारण OutOfMemory का कारण बनता है। https://github.com/andstatus/andstatus/issues/351 देखें एकमात्र समाधान जिसे मैं अभी कोशिश करना चाहता हूं, एक बार छवि कैश आवंटित करना है और फिर कैश किए गए बिटमा का पुन: उपयोग करना है पीएस स्मृति। पुन: प्रयोज्य होने के लिए मुझे अधिकतम आकार के बिटमैप आवंटित करना होगा ... – yvolk

4

यहाँ एक और एसओ पेज जाहिरा तौर पर इस समस्या के लिए एक समाधान है कि:

Strange out of memory issue while loading an image to a Bitmap object

विशेष रूप से, एप्रैम (कुछ अंश) द्वारा जवाब:

"1) हर बार जब आप BitmapFactory है। decodeXYZ(), BitmapFactory.Options में पास करने के लिए सुनिश्चित करें कि पूर्ण में सेट करने योग्य सेट (और अधिमानतः इनपूटशेयरबल के साथ भी सत्य पर सेट किया गया है)

"2) कभी भी बिटमैप.क्रेट बिटमैप (चौड़ाई, ऊंचाई, Config.A का उपयोग न करें) RGB_8888)। मेरा मतलब कभी नहीं है! मैंने कभी ऐसा नहीं किया है कि कुछ गुजरने के बाद मेमोरी त्रुटि नहीं बढ़ी है। रीसायकल(), System.gc() की कोई मात्रा नहीं, जो भी मदद की। यह हमेशा अपवाद उठाया। वास्तव में काम करने वाला एक अन्य तरीका है आपके ड्रॉबल्स में एक डमी छवि (या ऊपर दिए गए चरण 1 का उपयोग करके डीकोड किया गया एक और बिटमैप), जो कुछ भी आप चाहते हैं उसे पुन: प्राप्त करें, फिर परिणामी बिटमैप (जैसे इसे कैनवास पर पास करना) अधिक मज़ा के लिए)। तो, इसके बजाय आपको क्या उपयोग करना चाहिए: Bitmap.createScaledBitmap (srcBitmap, चौड़ाई, ऊंचाई, झूठी)। यदि किसी भी कारण से आपको ब्रूट फोर्स का उपयोग विधि का उपयोग करना चाहिए, तो कम से कम Config.ARGB_4444 को पास करें। "

टिप्पणियों में, कुछ लोगों ने कहा कि इससे उनकी समस्या हल हो गई है, जो ओपी के समान ही है।

मैं जोड़ता हूं कि डियान हैकबर्न ने टिप्पणी की है कि 3.0 एंड्रॉइड अब देशी ढेर से बिटमैप्स आवंटित नहीं करता है बल्कि इसके बजाय उन्हें नियमित ढेर से सीधे आवंटित करता है। इससे आपके मूल ढेर के आंकड़े अप्रासंगिक हो सकते हैं। इस पृष्ठ पर हैकबॉड की टिप्पणी देखें:

Bitmaps in Android

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

अंत में,

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

http://developer.android.com/training/displaying-bitmaps/manage-memory.html

मूल रूप से वे का उपयोग करने की सलाह देते हैं:

Detect application heap size in Android

+0

'inPurgeable' अब बहिष्कृत और अनदेखा कर दिया गया है। – zyamys

-2

वहाँ एंड्रॉयड developer.android.com पर बिटमैप स्मृति प्रबंधन के बारे में एक बहुत ही विस्तृत लेख है: यह तो जवाब इस की चर्चा भी शामिल है Android 2.3.3 और उसके बाद के लिए OutOfMemoryError त्रुटियों से बचने के लिए Bitmap.recycle()।प्रलेखन के अनुसार यह बिटमैप ऑब्जेक्ट से जुड़े मूल वस्तु को मुक्त करता है।

+0

वह 3.1 का उपयोग कर रहा है, जहां Bitmap.recycle() को अब सीधे कॉल करने की आवश्यकता नहीं है। –

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