2012-08-22 10 views
6

जैसा कि शीर्षक कहता है, मेरे पास लेआउट लोड करने पर स्मृति अपवाद को फेंक दिया गया है। एक सोचता है कि यह एक स्मृति रिसाव मुद्दा है, लेकिन इसे 2 दिनों के लिए लड़ने के बाद अब मुझे इतना यकीन नहीं है। ऐप में 10+ गतिविधियां हैं, जिनमें से अधिकांश पृष्ठभूमि छवियां हैं।OutOfMemoryError बिटमैप्स बनाने

कुछ तथ्यों/खोजों मैंने बनाया:

  • अब तक इस मुद्दे को केवल Android 4.0.3 चल Galaxy Nexus के लिए प्रकट होता है। मैं नेक्सस एस (4.1.1) और गैलेक्सी एस II (2.3.3) पर इसे पुन: उत्पन्न करने में असमर्थ था।

  • स्क्रीन अभिविन्यास बदल नहीं है। वास्तव में मेरी अधिकांश गतिविधियां वैसे भी पोर्ट्रेट पर बंद हो गईं।

  • सिर्फ हंसी के लिए मैंने नई गतिविधि खोलते समय finish() पर कॉल जोड़ा, इसलिए उस समय स्मृति में एक से अधिक गतिविधि नहीं होगी। सत्यापित है कि onDestroy कहा जा रहा है।

परिभाषित:

@Override 
public void onDestroy() 
{ 
    super.onDestroy(); 
    cleanupDrawables(contentView); 

    // null all the fields referencing views and drawables 

    System.gc(); 
} 

जहां cleanupDrawables() है:

protected static void cleanupDrawables(View view) 
{ 
    cleanupDrawable(view.getBackground()); 

    if (view instanceof ImageView) 
     cleanupDrawable(((ImageView)view).getDrawable()); 
    else if (view instanceof TextView) 
    { 
     TextView tv = (TextView)view; 
     Drawable[] compounds = tv.getCompoundDrawables(); 
     for (int i = 0; i < compounds.length; i++) 
      cleanupDrawable(compounds[i]); 
    } 
    else if (view instanceof ViewGroup && !(view instanceof AdapterView)) 
    { 
     ViewGroup vg = (ViewGroup)view; 
     for (int i = 0; i < vg.getChildCount(); i++) 
      cleanupDrawables(vg.getChildAt(i)); 
     vg.removeAllViews(); 
    } 
} 

protected static void cleanupDrawable(Drawable d) 
{ 
    if (d == null) 
     return; 

    d.setCallback(null); 

    if (d instanceof BitmapDrawable) 
     ((BitmapDrawable)d).getBitmap().recycle(); 
    else if (d instanceof LayerDrawable) 
    { 
     LayerDrawable layers = (LayerDrawable)d; 
     for (int i = 0; i < layers.getNumberOfLayers(); i++) 
      cleanupDrawable(layers.getDrawable(i)); 
    } 
} 
  • ग्रहण ढेर निरीक्षक को देखते हुए, स्मृति स्थिर प्रतीत होता है, यानी कुछ गतिविधियों को और अधिक स्मृति ले दूसरों की तुलना में, लेकिन इसे बंद करने पर जारी किया जाता है, और यह समय के साथ स्थिर दिखाई देता है।

  • एसओ छवियों पर संबंधित उत्तरों के अनुसार मूल स्मृति में संग्रहीत किया जाता है, लेकिन this दोस्त का दावा है कि उन्हें एंड्रॉइड 3 के बाद से ढेर पर होना चाहिए, इसलिए अगर यह वास्तव में छवि स्मृति रिसाव था तो मुझे स्मृति वृद्धि दिखाई देनी चाहिए।

मेरे प्रयासों का अंतिम परिणाम यह है कि मुझे अभी भी स्मृति त्रुटि से बाहर निकलना है, हालांकि जितना तेज़ मैंने पहले किया था। त्रुटि होने से पहले मैं दृश्यमान बिटमैप भ्रष्टाचार देखना शुरू कर देता हूं, जो cleanupDrawables() कोड जोड़ने से पहले मामला नहीं था। मैंने यह अनुमान लगाया कि Bitmap.recycle() पर कॉल भ्रष्टाचार का कारण बन रहा है, भले ही यह कोड केवल onDestroy पर कॉल किया गया हो। भ्रष्टाचार दोनों बिटमैप्स पर दिखाई देता है जो कई गतिविधियों पर दिखाई देने वाली सामान्य शैलियों के कुछ हिस्सों के साथ-साथ बिटमैप केवल एक गतिविधि पर दिखाए जाते हैं।

मेरी जांच के कम परिणामों में बल्कि असुविधाजनक हैं। इस बिंदु पर मुझे नहीं पता कि और क्या प्रयास करना है।

संदर्भ के लिए त्रुटि स्टैक ट्रेस: ​​

08-22 10:49:51.889: E/AndroidRuntime(31697): java.lang.RuntimeException: Unable to start activity ComponentInfo{klick.beatbleeds/klick.beatbleeds.Bleeds}: android.view.InflateException: Binary XML file line #67: Error inflating class <unknown> 
08-22 10:49:51.889: E/AndroidRuntime(31697): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1955) 
08-22 10:49:51.889: E/AndroidRuntime(31697): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1980) 
08-22 10:49:51.889: E/AndroidRuntime(31697): at android.app.ActivityThread.access$600(ActivityThread.java:122) 
08-22 10:49:51.889: E/AndroidRuntime(31697): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1146) 
08-22 10:49:51.889: E/AndroidRuntime(31697): at android.os.Handler.dispatchMessage(Handler.java:99) 
08-22 10:49:51.889: E/AndroidRuntime(31697): at android.os.Looper.loop(Looper.java:137) 
08-22 10:49:51.889: E/AndroidRuntime(31697): at android.app.ActivityThread.main(ActivityThread.java:4340) 
08-22 10:49:51.889: E/AndroidRuntime(31697): at java.lang.reflect.Method.invokeNative(Native Method) 
08-22 10:49:51.889: E/AndroidRuntime(31697): at java.lang.reflect.Method.invoke(Method.java:511) 
08-22 10:49:51.889: E/AndroidRuntime(31697): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784) 
08-22 10:49:51.889: E/AndroidRuntime(31697): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551) 
08-22 10:49:51.889: E/AndroidRuntime(31697): at dalvik.system.NativeStart.main(Native Method) 
08-22 10:49:51.889: E/AndroidRuntime(31697): Caused by: android.view.InflateException: Binary XML file line #67: Error inflating class <unknown> 
08-22 10:49:51.889: E/AndroidRuntime(31697): at android.view.LayoutInflater.createView(LayoutInflater.java:606) 
08-22 10:49:51.889: E/AndroidRuntime(31697): at com.android.internal.policy.impl.PhoneLayoutInflater.onCreateView(PhoneLayoutInflater.java:56) 
08-22 10:49:51.889: E/AndroidRuntime(31697): at android.view.LayoutInflater.onCreateView(LayoutInflater.java:653) 
08-22 10:49:51.889: E/AndroidRuntime(31697): at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:678) 
08-22 10:49:51.889: E/AndroidRuntime(31697): at android.view.LayoutInflater.rInflate(LayoutInflater.java:739) 
08-22 10:49:51.889: E/AndroidRuntime(31697): at android.view.LayoutInflater.inflate(LayoutInflater.java:489) 
08-22 10:49:51.889: E/AndroidRuntime(31697): at android.view.LayoutInflater.inflate(LayoutInflater.java:396) 
08-22 10:49:51.889: E/AndroidRuntime(31697): at android.view.LayoutInflater.inflate(LayoutInflater.java:352) 
08-22 10:49:51.889: E/AndroidRuntime(31697): at klick.beatbleeds.ActivityBase.setContentView(ActivityBase.java:82) 
08-22 10:49:51.889: E/AndroidRuntime(31697): at klick.beatbleeds.Bleeds.onCreate(Bleeds.java:40) 
08-22 10:49:51.889: E/AndroidRuntime(31697): at android.app.Activity.performCreate(Activity.java:4465) 
08-22 10:49:51.889: E/AndroidRuntime(31697): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1049) 
08-22 10:49:51.889: E/AndroidRuntime(31697): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1919) 
08-22 10:49:51.889: E/AndroidRuntime(31697): ... 11 more 
08-22 10:49:51.889: E/AndroidRuntime(31697): Caused by: java.lang.reflect.InvocationTargetException 
08-22 10:49:51.889: E/AndroidRuntime(31697): at java.lang.reflect.Constructor.constructNative(Native Method) 
08-22 10:49:51.889: E/AndroidRuntime(31697): at java.lang.reflect.Constructor.newInstance(Constructor.java:417) 
08-22 10:49:51.889: E/AndroidRuntime(31697): at android.view.LayoutInflater.createView(LayoutInflater.java:586) 
08-22 10:49:51.889: E/AndroidRuntime(31697): ... 23 more 
08-22 10:49:51.889: E/AndroidRuntime(31697): Caused by: java.lang.OutOfMemoryError 
08-22 10:49:51.889: E/AndroidRuntime(31697): at android.graphics.Bitmap.nativeCreate(Native Method) 
08-22 10:49:51.889: E/AndroidRuntime(31697): at android.graphics.Bitmap.createBitmap(Bitmap.java:605) 
08-22 10:49:51.889: E/AndroidRuntime(31697): at android.graphics.Bitmap.createBitmap(Bitmap.java:551) 
08-22 10:49:51.889: E/AndroidRuntime(31697): at android.graphics.Bitmap.createScaledBitmap(Bitmap.java:437) 
08-22 10:49:51.889: E/AndroidRuntime(31697): at android.graphics.BitmapFactory.finishDecode(BitmapFactory.java:524) 
08-22 10:49:51.889: E/AndroidRuntime(31697): at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:499) 
08-22 10:49:51.889: E/AndroidRuntime(31697): at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:351) 
08-22 10:49:51.889: E/AndroidRuntime(31697): at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:773) 
08-22 10:49:51.889: E/AndroidRuntime(31697): at android.content.res.Resources.loadDrawable(Resources.java:1937) 
08-22 10:49:51.889: E/AndroidRuntime(31697): at android.content.res.TypedArray.getDrawable(TypedArray.java:601) 
08-22 10:49:51.889: E/AndroidRuntime(31697): at android.view.View.<init>(View.java:2780) 
08-22 10:49:51.889: E/AndroidRuntime(31697): at android.view.ViewGroup.<init>(ViewGroup.java:385) 
08-22 10:49:51.889: E/AndroidRuntime(31697): at android.widget.LinearLayout.<init>(LinearLayout.java:174) 
08-22 10:49:51.889: E/AndroidRuntime(31697): at android.widget.LinearLayout.<init>(LinearLayout.java:170) 
08-22 10:49:51.889: E/AndroidRuntime(31697): ... 26 more 

यहाँ दृश्यों में से एक का एक स्क्रीनशॉट कितने छवियों यहाँ उपयोग किया जाता है enter image description here

+0

तो, कितना बड़ा इन बिटमैप्स (संकल्प) कर रहे हैं? यदि आप उन्हें छोटी छवियों (केवल किक्स के लिए) के साथ बदलते हैं, तो क्या समस्याएं दूर हो जाती हैं? – dmon

+0

दृश्य से क्लीनअप बिटमैप संसाधन आवश्यक नहीं है और केवल एक नई गतिविधि में आपका संक्रमण धीमा कर देगा। आप किस प्रकार का लेआउट फुला रहे हैं और कितनी छवियों के साथ? – DeeV

+0

मैं @Deev से भी सहमत हूं, आपको नष्ट करने पर अपने बिटमैप्स मैन्युअल रूप से "साफ" करने की आवश्यकता नहीं है। – dmon

उत्तर

2

खोजने के लिए इन स्थिर विधियों का उपयोग करने के विचार प्राप्त करने के लिए है बाहर सटीक समस्या (ओं):

public static void showBitmapSize(Bitmap bitmap) { 
    Log.d("test", "bitmap dimensions: w:" + bitmap.getWidth() + ", h:" + bitmap.getHeight() + " memory: " + (bitmap.getRowBytes() * bitmap.getHeight()/1048576d)); 
} 

और सबसे महत्वपूर्ण:

static double lastavail; 
static double initavail; 
static boolean first = true; 

public static void showMemoryStats() { 
    showMemoryStats(""); 
} 

public static void showMemoryStats(String message) { 
    Log.i("memory", message + "----------------------------------------------------------------------------------------"); 
    double nativeUsage = Debug.getNativeHeapAllocatedSize(); 
    Log.i("memory", "nativeUsage: " + (nativeUsage/1048576d)); 
    //current heap size 
    double heapSize = Runtime.getRuntime().totalMemory(); 
//  Log.i("memory", "heapSize: " + (heapSize/1048576d)); 
    //amount available in heap 
    double heapRemaining = Runtime.getRuntime().freeMemory(); 
//  Log.i("memory", "heapRemaining: " + (heapRemaining/1048576d)); 
    double memoryAvailable = Runtime.getRuntime().maxMemory() - (heapSize - heapRemaining) - nativeUsage; 
    Log.i("memory", "memoryAvailable: " + (memoryAvailable/1048576d)); 

    if (first) { 
     initavail = memoryAvailable; 
     first = false; 
    } 
    if (lastavail > 0) { 
     Log.i("memory", "consumed since last: " + ((lastavail - memoryAvailable)/1048576d)); 
    } 
    Log.i("memory", "consumed total: " + ((initavail - memoryAvailable)/1048576d)); 

    lastavail = memoryAvailable; 

    Log.i("memory", "-----------------------------------------------------------------------------------------------"); 
} 

1048576 द्वारा विभाजित केवल एमबी में मूल्य प्राप्त करने के लिए है (कम से कम मेरे लिए एमबी में सोचना आसान है)।

पर setContentView() कॉल से पहले कुछ सार्थक संदेश के साथ कॉल करें, और उसके बाद दूसरा। और जब आप एक नई गतिविधि शुरू करते हैं, तो अंत में आप अपनी समस्या के सटीक कारण होंगे।

मैनुअल रीसाइक्लिंग के लिए आवश्यक हो सकता है। मुझे इसे अपने ऐप में कुछ स्थानों पर लागू करना पड़ा। बिटमैप-गहन एक (कई पृष्ठभूमि और चित्र) का उपयोग करके और सभी उपकरणों में इस तरह की समस्याएं थीं। इन तरीकों से मैं सभी समस्याओं को ढूंढने और एप्रोपीएटेड तरीके से संभालने में सक्षम था।

आह। और आपकी समस्या के लिए एक तेज़ तेज़ समाधान है, आप कहते हैं कि यह केवल गैलेक्सी नेक्सस में दिखाई देता है। आपके द्वारा उल्लेख किए गए एकमात्र xhdpi डिवाइस है। आपके पास शायद फ़ोल्डर ड्रायबल या ड्रायबल-एचडीपीआई में सभी बिटमैप हैं। Xhdpi डिवाइस बिटमैप को ड्रॉबल या ड्रॉबल-एचडीपीआई से ले जाएगा और स्केल अप करेगा (हालांकि वे पहले से ही सही आकार में हो सकते हैं), और यह बहुत सारी मेमोरी का उपभोग करेगा। समाधान: यदि अस्तित्व में नहीं है, तो drawable-xhdpi फ़ोल्डर बनाएं, और वहां बिटमैप्स की प्रतिलिपि रखें।

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