2011-10-14 8 views
13

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

10-14 13:43:53.020: INFO/dalvikvm-heap(31533): Grow heap (frag case) to 40.637MB for 942134-byte allocation 
    10-14 13:43:53.070: DEBUG/dalvikvm(31533): GC_FOR_ALLOC freed 126K, 11% free 41399K/46343K, paused 31ms 
    10-14 13:43:53.130: DEBUG/dalvikvm(31533): GC_FOR_ALLOC freed 920K, 13% free 40478K/46343K, paused 30ms 
    10-14 13:43:53.180: DEBUG/dalvikvm(31533): GC_FOR_ALLOC freed 1026K, 13% free 40479K/46343K, paused 30ms 
    10-14 13:43:53.250: DEBUG/dalvikvm(31533): GC_FOR_ALLOC freed 931K, 12% free 41193K/46343K, paused 31ms 
    10-14 13:43:53.250: INFO/dalvikvm-heap(31533): Grow heap (frag case) to 41.313MB for 1048592-byte allocation 
    10-14 13:43:53.280: DEBUG/dalvikvm(31533): GC_FOR_ALLOC freed <1K, 11% free 42217K/47431K, paused 31ms 
    10-14 13:44:01.520: DEBUG/dalvikvm(31533): GC_CONCURRENT freed 3493K, 15% free 40646K/47431K, paused 3ms+9ms 
    10-14 13:44:08.130: DEBUG/dalvikvm(31533): GC_EXPLICIT freed 16461K, 47% free 25527K/47431K, paused 3ms+6ms 
    10-14 13:44:09.150: DEBUG/dalvikvm(31533): GC_FOR_ALLOC freed 1007K, 45% free 26191K/47431K, paused 35ms 
    10-14 13:44:09.160: INFO/dalvikvm-heap(31533): Grow heap (frag case) to 29.334MB for 3850256-byte allocation 
    10-14 13:44:09.200: DEBUG/dalvikvm(31533): GC_CONCURRENT freed 0K, 37% free 29951K/47431K, paused 2ms+4ms 
    10-14 13:44:11.970: DEBUG/dalvikvm(31533): GC_FOR_ALLOC freed 1878K, 38% free 29784K/47431K, paused 37ms 
    10-14 13:44:12.410: DEBUG/dalvikvm(31533): GC_FOR_ALLOC freed 62K, 36% free 30441K/47431K, paused 32ms 
    10-14 13:44:12.440: DEBUG/dalvikvm(31533): GC_FOR_ALLOC freed <1K, 32% free 32325K/47431K, paused 32ms 
    10-14 13:44:12.440: INFO/dalvikvm-heap(31533): Forcing collection of SoftReferences for 3850256-byte allocation 
    10-14 13:44:12.480: DEBUG/dalvikvm(31533): GC_BEFORE_OOM freed 124K, 33% free 32200K/47431K, paused 37ms 
    10-14 13:44:12.480: ERROR/dalvikvm-heap(31533): Out of memory on a 3850256-byte allocation. 

मैं बहुत लॉगिंग सहित क्षमा चाहता हूं, मुझे उम्मीद है कि यह प्रासंगिक है। जिस तरह से मैंने इसे पढ़ा है वह यह है कि सिस्टम अंततः ढेर आकार को तब तक समायोजित करता है जब तक कि अंततः ढेर अधिकतम तक पहुंच न जाए। फिर, हम एक विशेष रूप से बड़े आवंटन का अनुरोध करते हैं जो विफल रहता है। स्पष्ट रूप से पर्याप्त स्मृति उपलब्ध है (लगभग 15 मेगापिक्सल)। क्या इसका मतलब यह है कि ढेर आंतरिक रूप से खंडित है और हमारे आवंटन को संभालने के लिए पर्याप्त कोई संगत स्मृति खंड नहीं हैं? अगर ऐसा है तो मुझे क्या करना चाहिए? अगर ऐसा नहीं है, तो क्या?

अग्रिम धन्यवाद।

+0

आप softreferences का उपयोग कर रहे हैं? – Raunak

+0

सीधे नहीं, हालांकि तीसरी आखिरी पंक्ति सॉफ्ट रेफरेंस के बारे में कुछ कहती है। मैं एक Google-संग्रह आधारित कैश का उपयोग कर रहा हूं जो जहां तक ​​मुझे पता है वीक रेफरेंस का उपयोग करता है। – EightyEight

+0

मुझे ओएस 4.1.2 पर एक एस 3 पर एक ही समस्या दिखाई दे रही है, जाहिर है कि यहां तक ​​कि और भी अधिक मुफ्त मेमोरी उपलब्ध है: 10-02 14: 28: 22.458 5333 9044 डी दल्विकविक: जीसीबीईईएफटीओओओएम 0K, 54% मुक्त 30274 के/65543 के, 120ms रुका हुआ है, कुल 120ms –

उत्तर

16

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

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

मेरे पास यह छोटा बच्चा हाथ में है सभी समय:

public static void stripImageView(ImageView view) { 
    if (view.getDrawable() instanceof BitmapDrawable) { 
     ((BitmapDrawable)view.getDrawable()).getBitmap().recycle(); 
    } 
    view.getDrawable().setCallback(null); 
    view.setImageDrawable(null); 
    view.getResources().flushLayoutCache(); 
    view.destroyDrawingCache(); 
} 
+0

मुझे यकीन है कि मधुकोश Hege के लिए सही है नहीं कर रहा हूँ। छवियाँ एप्लिकेशन ढेर मेरा मानना ​​है कि पर आवंटित किए जाते हैं - यह गूगल आईओ 2011 बात (स्लाइड 18 http://static.googleusercontent.com/external_content/untrusted_dlcp/www.google.com/en//events/io/2011/ के आधार पर स्थिर/presofiles/memory_management_for_android_apps.pdf)। Anecdotally, मैं मेरे ऐप ढेर हो जाना जब मैं एक बड़े बिटमैप आवंटित देखते हैं, और हटना जब मैं इसे जारी (कोड क्या आप पोस्ट के लिए इसी तरह के साथ)> – EightyEight

+1

याप, मैं तुम्हें शायद Android 2.2 (या 2.3 से बता दिया है :) ") इस बदल गया है ... " – hege

+1

दुर्भाग्य से यह पर्याप्त है, यकीन नहीं क्यों होना करने के लिए प्रतीत नहीं होता। रीसायकल/आदि का ढेर आकार (कम से कम इस 4.0 डिवाइस पर) पर असर नहीं पड़ता है। –

2

छवियों वेब से लाई जाती हैं, 300K से लेकर 500K में आकार को लेकर प्रत्येक, और ड्रॉएबल की एक ArrayList में संग्रहीत।

वेब से लोड होने वाली छवि का केबी फ़ाइल आकार सीधे प्रासंगिक नहीं है। चूंकि वे बिटमैप्स में परिवर्तित हो जाते हैं, इसलिए आपको नियमित ARGB छवियों के लिए प्रति छवि चौड़ाई * ऊंचाई * 4 बाइट की गणना करने की आवश्यकता होती है। (पीएक्स में चौड़ाई और ऊंचाई)।

बिटमैप्स देशी ढेर का उपभोग करते हैं, जो आम तौर पर एक एचआरओफ़ में नहीं दिखता है। Hprof केवल आपको ऑब्जेक्ट्स की संख्या दिखाएगा, यानी बिटमैप ड्रावेबल्स या बिटमैप्स जो शेष हैं।

public static void logHeap(Class clazz) { 
    Double allocated = new Double(Debug.getNativeHeapAllocatedSize())/new Double((1048576)); 
    Double available = new Double(Debug.getNativeHeapSize())/1048576.0); 
    Double free = new Double(Debug.getNativeHeapFreeSize())/1048576.0); 
    DecimalFormat df = new DecimalFormat(); 
    df.setMaximumFractionDigits(2); 
    df.setMinimumFractionDigits(2); 

    Log.d(APP, "debug. ================================="); 
    Log.d(APP, "debug.heap native: allocated " + df.format(allocated) + "MB of " + df.format(available) + "MB (" + df.format(free) + "MB free) in [" + clazz.getName().replaceAll("com.myapp.android.","") + "]"); 
    Log.d(APP, "debug.memory: allocated: " + df.format(new Double(Runtime.getRuntime().totalMemory()/1048576)) + "MB of " + df.format(new Double(Runtime.getRuntime().maxMemory()/1048576))+ "MB (" + df.format(new Double(Runtime.getRuntime().freeMemory()/1048576)) +"MB free)"); 
    System.gc(); 
    System.gc(); 

    // don't need to add the following lines, it's just an app specific handling in my app   
    if (allocated>=(new Double(Runtime.getRuntime().maxMemory())/new Double((1048576))-MEMORY_BUFFER_LIMIT_FOR_RESTART)) { 
     android.os.Process.killProcess(android.os.Process.myPid()); 
    } 
} 

जो मैं फोन जब शुरू करने या विकास के दौरान एक गतिविधि परिष्करण:

मैं वर्तमान इस्तेमाल किया स्मृति एप्लिकेशन और देशी ढेर द्वारा इस्तेमाल किया उत्पादन के लिए मेरे एप्लिकेशन में इस कोड का उपयोग।

logHeap(this.getClass()); 

यहां कुछ जानकारीपूर्ण लिंक हैं - आम तौर पर यहां इस विषय के बारे में बहुत सारे धागे हैं।

यहाँ भी रोमेन लड़का (एंड्रॉयड फ्रेमवर्क इंजीनियर) नरम संदर्भ, कमजोर संदर्भ, सरल कैश, छवि से निपटने के बारे में द्वारा एक उपयोगी स्लाइड है: http://docs.huihoo.com/google/io/2009/Th_0230_TurboChargeYourUI-HowtomakeyourAndroidUIfastandefficient.pdf

+0

मेहुल के जवाब के लिए धन्यवाद। दुर्भाग्यवश आपके सभी संसाधन हनीकॉम का अनुमान लगाते हैं। मैं आपके स्रोत कोड की जांच करूंगा। – EightyEight

0

हाँ "मेमोरी से बाहर" त्रुटि तब होती है जब हम बड़े आकार के बिटमैप के साथ काम कर रहे होते हैं। इसके लिए मेरे पास एक समाधान है, छवि के डीकोडिंग के साथ हम आसानी से इस त्रुटि से बच सकते हैं।

BitmapFactory.Options o = new BitmapFactory.Options(); 
o.inJustDecodeBounds = true; 
FileInputStream fis = new FileInputStream(files.getAbsolutePath()); 
BitmapFactory.decodeStream(fis, null, o); 
fis.close(); 
final int REQUIRED_SIZE=70; 
int width_tmp=o.outWidth, height_tmp=o.outHeight; 
int scale=1; 
while(true){ 
if(width_tmp/2<REQUIRED_SIZE || height_tmp/2<REQUIRED_SIZE) 
break; 
width_tmp/=2; 
height_tmp/=2; 
scale*=2; 
} 
BitmapFactory.Options op = new BitmapFactory.Options(); 
op.inSampleSize = scale; 
fis = new FileInputStream(files.getAbsolutePath()); 
bitmap[i] = BitmapFactory.decodeStream(fis, null, op); 
fis.close(); 
+1

तो जब आप ओओएम प्राप्त करते हैं तो आप छवि को फिर से सहेज रहे हैं? मुझे लगता है कि यह एक संभावित समाधान है, लेकिन यह मेरे मूल प्रश्न का उत्तर नहीं देता है। – EightyEight

0

सिस्टम ढेर आकार को समायोजित नहीं करता है। आपके ऐप में एक (सेमी-) पूर्वनिर्धारित ढेर स्थान है। हीप आकार कुछ कस्टम रोम में समायोजित किया जा सकता है। यह वास्तव में आपकी समस्या के लिए जर्मन नहीं है।

कचरा संग्रहण आप देख रहे हैं के आदेश का सुझाव देने के GC_BEFORE_OOM के समय आपके एप्लिकेशन की अपनी ढेर में स्थान कम होता है कि लगता है। दल्विक लॉगर द्वारा रिपोर्ट किए गए आंकड़े सिस्टम-व्यापी हो सकते हैं।

+1

ब्रैकेट्स में संख्या प्रक्रिया आईडी है, इसलिए रिपोर्ट किए गए आंकड़े प्रति प्रक्रिया हैं, सिस्टम व्यापक नहीं .. मैं इस असंगतता को हल करने की कोशिश कर रहा हूं। दलविक की 30% स्मृति उपलब्ध है और अगली पंक्ति इंगित करती है कि स्मृति समाप्त हो गई है। विचित्र। – EightyEight