android - एंड्रॉइड: BitmapFactory.decodeStream() 2 एमबी फ्री ढेर के साथ 400 केबी फाइल के साथ मेमोरी से बाहर




heap (5)

मेरा ऐप स्रोत में निम्न पंक्ति पर ओओएम त्रुटि मार रहा है:

image = BitmapFactory.decodeStream(assetManager.open(imgFilename));

ओओएम त्रुटि के साथ ऐप को मारने के कारण होने वाले आवंटन से ठीक पहले:

(...)
08-05 21:22:12.443: I/dalvikvm-heap(2319): Clamp target GC heap from 25.056MB to 24.000MB
08-05 21:22:12.443: D/dalvikvm(2319): GC_FOR_MALLOC freed <1K, 50% free 2709K/5379K, external 18296K/19336K, paused 58ms
08-05 21:22:14.513: D/dalvikvm(2319): GC_EXTERNAL_ALLOC freed <1K, 50% free 2709K/5379K, external 18296K/19336K, paused 101ms
08-05 21:22:14.903: I/dalvikvm-heap(2319): Clamp target GC heap from 25.073MB to 24.000MB
08-05 21:22:14.903: D/dalvikvm(2319): GC_FOR_MALLOC freed 0K, 50% free 2709K/5379K, external 18312K/19336K, paused 53ms
08-05 21:22:22.843: D/ddm-heap(2319): Heap GC request
08-05 21:22:22.963: I/dalvikvm-heap(2319): Clamp target GC heap from 25.073MB to 24.000MB
08-05 21:22:22.963: D/dalvikvm(2319): threadid=1: still suspended after undo (sc=1 dc=1)
08-05 21:22:22.963: D/dalvikvm(2319): GC_EXPLICIT freed 1K, 50% free 2710K/5379K, external 18312K/19336K, paused 116ms

डीडीएमएस ढेर की स्थिति के बारे में एक समान तस्वीर की रिपोर्ट करता है:

Heap Size:  5.254 MB
Allocated:  2.647 MB
Free:   2.607 MB
%Used:  50.38%
#Objects    49,028  

इस लाइन पर सिंगल स्टेपिंग के परिणामस्वरूप ओओएम त्रुटि होती है:

08-05 21:26:04.783: D/dalvikvm(2319): GC_EXTERNAL_ALLOC freed <1K, 50% free 2710K/5379K, external 18312K/19336K, paused 57ms
08-05 21:26:05.023: E/dalvikvm-heap(2319): 2097152-byte external allocation too large for this process.
08-05 21:26:05.163: I/dalvikvm-heap(2319): Clamp target GC heap from 25.073MB to 24.000MB
08-05 21:26:05.163: E/GraphicsJNI(2319): VM won't let us allocate 2097152 bytes
08-05 21:26:05.163: D/dalvikvm(2319): GC_FOR_MALLOC freed 0K, 50% free 2710K/5379K, external 18312K/19336K, paused 30ms
08-05 21:26:05.283: D/skia(2319): --- decoder->decode returned false
  1. "ImgFileName" द्वारा संदर्भित फ़ाइल का आकार Windows पर <400K होने की सूचना दी गई है। तो BitmapFactory.decodeStream 2 एमबी आवंटित करने का प्रयास क्यों करता है?
  2. पर्याप्त खाली जगह होने पर ओओएम त्रुटि क्यों होती है?

यह ऐप एंड्रॉइड 2.2 और ऊपर लक्षित कर रहा है।

अग्रिम में धन्यवाद!


छवियों को लोड करने के लिए एंड्रॉइड लाइब्रेरी इतना स्मार्ट नहीं है, इसलिए आपको इसके लिए वर्कअराउंड बनाना होगा।

मेरे परीक्षणों में, Drawable.createFromStream BitmapFactory.decodeStream तुलना में अधिक मेमोरी का उपयोग करता है।

आप स्मृति योजना (RGB_565) को कम करने के लिए रंग योजना बदल सकते हैं, लेकिन छवि गुणवत्ता भी खो जाएगी:

BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Config.RGB_565;
Bitmap bitmap = BitmapFactory.decodeStream(stream, null, options);

संदर्भ: http://developer.android.com/reference/android/graphics/Bitmap.Config.html

आप एक स्केल की गई छवि भी लोड कर सकते हैं, जो स्मृति उपयोग को बहुत कम कर देगा, लेकिन आपको अपनी छवियों को बहुत अधिक गुणवत्ता खोने के लिए नहीं जानना होगा।

BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;
Bitmap bitmap = BitmapFactory.decodeStream(stream, null, options);

संदर्भ: http://developer.android.com/reference/android/graphics/BitmapFactory.Options.html

गतिशील रूप से inSampleSize को परिभाषित करने के लिए, आप अपना निर्णय लेने के लिए छवि आकार जानना चाहेंगे:

BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
bitmap = BitmapFactory.decodeStream(stream, null, options);
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;

options.inJustDecodeBounds = false;
// recreate the stream
// make some calculation to define inSampleSize
options.inSampleSize = ?;
Bitmap bitmap = BitmapFactory.decodeStream(stream, null, options);

आप डिवाइस के स्क्रीन आकार के अनुसार inSampleSize को कस्टमाइज़ कर सकते हैं। स्क्रीन आकार प्राप्त करने के लिए, आप यह कर सकते हैं:

DisplayMetrics metrics = new DisplayMetrics();
((Activity) activity).getWindowManager().getDefaultDisplay().getMetrics(metrics);
int screenWidth = metrics.widthPixels;
int screenHeight =metrics.heightPixels;

अन्य ट्यूटोरियल: - http://developer.android.com/training/displaying-bitmaps/load-bitmap.html - http://developer.android.com/training/displaying-bitmaps/index.html


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


बड़ी बिटमैप्स को अधिक कुशलता से लोड करने पर मार्गदर्शिका के लिए कृपया इसे देखें:

http://developer.android.com/training/displaying-bitmaps/load-bitmap.html

एक 400 केबी छवि फ़ाइल आसानी से 5-10 एमबी रैम ले सकती है।


मूल रूप से आप अपने Bitmap को स्केल करने की कोशिश करके अपनी समस्या का समाधान कर सकते हैं और आपको स्मृति खपत कम दिखाई देगी। ऐसा करने के लिए आप here दिखाए गए तरीके की प्रतिलिपि बना सकते here ।

साथ ही, एंड्रॉइड डेवलपर्स में एक समर्पित पृष्ठ है जो आपको बड़ी बिटमैप्स को लोड करने के तरीके को बेहतर ढंग से समझने में मदद कर सकता है। आधिकारिक http://developer.android.com/training/displaying-bitmaps/load-bitmap.html पर एक नज़र डालें।


मैंने नीचे विधि का उपयोग कर OutOfMemoryError समस्या का समाधान किया

private Bitmap downloadImageBitmap(String sUrl) {
        this.url = sUrl;
        bitmap = null;
                    try {
            BitmapFactory.Options options = new BitmapFactory.Options();
            for (options.inSampleSize = 1; options.inSampleSize <= 32; options.inSampleSize++) {
                InputStream inputStream = new URL(sUrl).openStream();  
                try {
                    bitmap = BitmapFactory.decodeStream(inputStream, null, options);      
                    inputStream.close();
                    break;
                } catch (OutOfMemoryError outOfMemoryError) {
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return bitmap;
    }






heap