Android: बिटमैप रीसायकल () कैसे काम करता है?


89

मान लीजिए कि मैंने एक बिटमैप ऑब्जेक्ट में एक छवि लोड की है जैसे

Bitmap myBitmap = BitmapFactory.decodeFile(myFile);

अब, अगर मैं एक और बिटमैप लोड करूँ तो क्या होगा

myBitmap = BitmapFactory.decodeFile(myFile2);

पहले myBitmap का क्या होता है? क्या यह कचरा एकत्रित हो जाता है या क्या मुझे दूसरे बिटमैप को लोड करने से पहले मैन्युअल रूप से कचरा इकट्ठा करना होगा, जैसे। myBitmap.recycle()?

इसके अलावा, क्या बड़ी छवियों को लोड करने और रास्ते में रीसाइक्लिंग के दौरान उन्हें एक के बाद एक प्रदर्शित करने का एक बेहतर तरीका है?

जवाबों:


79

जब आप दूसरे को डीकोड करते हैं तो पहला बिटमैप कचरा एकत्र नहीं किया जाता है । जब भी निर्णय होगा कचरा कलेक्टर इसे बाद में करेगा। यदि आप मेमोरी को ASAP मुक्त करना चाहते हैं तो आपको कॉल करना चाहिएrecycle() दूसरे बिटमैप को डिकोड करने से ठीक पहले ।

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


23

मुझे लगता है कि समस्या यह है: एंड्रॉइड के पूर्व-हनीकॉम्ब संस्करणों पर, वास्तविक कच्चे बिटमैप डेटा को वीएम मेमोरी में संग्रहीत नहीं किया जाता है, बल्कि देशी मेमोरी में। यह देशी स्मृति है जब इसी जावा मुक्त कर दिया Bitmapवस्तु GC'd है।

हालाँकि , जब आप मूल मेमोरी से बाहर निकलते हैं, तो dalvik GC ट्रिगर नहीं होता है, इसलिए यह संभव है कि आपका ऐप जावा मेमोरी का बहुत कम उपयोग करता है, इसलिए dalvik GC को कभी भी इनवॉइस नहीं किया जाता है, फिर भी यह बिटकैप के लिए देशी मेमोरी का उपयोग करता है। जो अंततः OOM त्रुटि का कारण बनता है।

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


21

अगली छवि लोड करने से पहले आपको myBitmap.recycle () पर कॉल करना होगा।

आपके myFile के स्रोत पर निर्भर करता है (जैसे यदि यह ऐसा कुछ है जिसका आपके पास मूल आकार पर कोई नियंत्रण नहीं है), जब किसी छवि को लोड करने के बजाय बस कुछ मनमाना संख्या को फिर से खोलना हो, तो आपको छवि को प्रदर्शन आकार में स्केल करना चाहिए।

if (myBitmap != null) {
    myBitmap.recycle();
    myBitmap = null;
}
Bitmap original = BitmapFactory.decodeFile(myFile);
myBitmap = Bitmap.createScaledBitmap(original, displayWidth, displayHeight, true);
if (original != myBitmap)
    original.recycle();
original = null;

मैं प्रदर्शन को प्रदर्शित करता हूं और प्रदर्शन को स्थिर करता हूं जिसे मैंने अपनी गतिविधि की शुरुआत में शुरू किया था।

Display display = getWindowManager().getDefaultDisplay();
displayWidth = display.getWidth();
displayHeight = display.getHeight();

3
आपको रीसायकल () को कॉल करने की आवश्यकता नहीं है, यह सिर्फ एक अच्छा विचार है यदि आप स्मृति को तुरंत मुक्त करना चाहते हैं।
कारू

13
स्वीकृत उत्तर कहता है "यदि आप एएसएपी को मेमोरी से मुक्त करना चाहते हैं तो आपको रीसायकल ()" कॉल करना चाहिए। आपका उत्तर कहता है "आपको myBitmap.recycle ()" पर कॉल करना होगा। "चाहिए" और "की आवश्यकता" के बीच अंतर है, और इस मामले में उत्तरार्द्ध गलत है।
कारू

1
प्रसंग महत्वपूर्ण है। सवाल था "बड़ी छवियों को लोड करने और रास्ते में एक और रीसाइक्लिंग के बाद उन्हें प्रदर्शित करने का एक बेहतर तरीका है"।
दुनजोद

3
एंड्रॉइड 4.1 के रूप में, उपरोक्त उदाहरण टूट सकता है क्योंकि createScaledBitmap कुछ मामलों में उसी के मूल के रूप में वापस आ सकता है। इसका मतलब है कि आपको मूल पुनरावर्तन से पहले उस मूल! = MyBitmap की जांच करनी होगी।
जेरेमीफा

1
@ जेरेमीफा यह केवल मूल छवि देता है यदि आप एक चौड़ाई और ऊंचाई निर्दिष्ट करते हैं जो मूल के समान है। उस मामले में, स्केलिंग मूट है, इसलिए यह इसे लंघन और इसके बजाय मूल छवि को वापस करके कुछ प्रक्रियाओं को बचा सकता है। यह कुछ भी "तोड़" नहीं करना चाहिए ...
Jabari

11

एक बार बिटमैप मेमोरी में लोड हो गया था, वास्तव में यह दो भाग डेटा द्वारा बनाया गया था। पहले भाग में बिटमैप के बारे में कुछ जानकारी शामिल है, दूसरे भाग में बिटमैप के पिक्सल के बारे में जानकारी शामिल है (इसे बाइट सरणी द्वारा बनाया गया है)। जावा इस्तेमाल की गई मेमोरी में पहले भाग के एक्सिसिट्स, दूसरे भाग के एक्सिसिट्स सी ++ उपयोग की गई मेमोरी में। यह सीधे एक दूसरे की मेमोरी का उपयोग कर सकते हैं। बिटमैप.क्रिसकिल () का उपयोग C ++ की मेमोरी को खाली करने के लिए किया जाता है। यदि आप केवल ऐसा करते हैं, तो जीसी जावा के हिस्से को एकत्र करेगा और सी की मेमोरी हमेशा उपयोग की जाती है।


+1 एक दिलचस्प लेकिन बहुत अच्छे तरीके से वर्णन करने के लिए कि मेमोरी तत्काल जीसी के लिए उपलब्ध क्यों नहीं है - अच्छा है।
रिचर्ड ले मेसुरियर

8

टिम्मम सही था।

इसके अनुसार: http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html

इसके अलावा, एंड्रॉइड 3.0 (एपीआई स्तर 11) से पहले, बिटमैप के बैकिंग डेटा को देशी मेमोरी में संग्रहित किया गया था, जो कि पूर्वानुमेय तरीके से जारी नहीं किया गया है, संभवतः किसी एप्लिकेशन को इसकी मेमोरी सीमा और क्रैश से अधिक हो सकता है।

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