2016-05-23 6 views
0

Ich entwickle derzeit eine Xamarin.Android App, die eine Menge von Aktivitäten enthält, arbeiten mit einer API, die Bilder und manchmal riesige Listen von Objekten zurückgeben, so muss ich auf Speicher zu kümmern Vermeiden Sie OOM.Speicherleck mit einfachen Aktivitäten Navigation

Aber es gelang mir schließlich, einige zu haben, als ich anfing, mit Bitmaps zu arbeiten. Zuerst dachte ich, es wäre wegen dieser Bitmaps, also habe ich ein paar Tests gemacht. Und es scheint, dass es nicht ist. Ich habe die API deaktiviert, also arbeite ich mit leeren Listen von Objekten und ohne Bilder. Und es ist mir immer noch gelungen, den Speicherverbrauch meiner App verrückt zu machen, um schließlich zu stürzen.

Da ich Xamarin Profiler auf Visual Studio nicht installieren kann (keine Ahnung warum, aber nicht das Hauptproblem hier), installierte ich eine App auf meinem Gerät (das ist ein OnePlus One), genannt Intel Performance Viewer ist in der Lage, die RAM-Nutzung des Geräts in Echtzeit zu überwachen. Ich starte meine App und sagen wir, die Speicherauslastung beträgt insgesamt 1,1 GB Speicherplatz. Ich klicke auf eine Schaltfläche, die eine Liste von Objekten anzeigen soll, aber da die API inaktiv ist, ist die Liste leer. Die Aktivität enthält also eine benutzerdefinierte Appbar, zwei Schaltflächen, eine leere Listenansicht und einen Text mit der Aufschrift "Liste ist leer". Der RAM-Verbrauch stieg von ca. 30MB, als dieser Vorgang aufgerufen wurde. Dann drücke ich meine Zurück-Taste, die ein Finish() ruft; auf die Aktivität, dann bin ich wieder am Main. Und der RAM-Verbrauch sinkt von gleich, ein oder zwei MB.

Dann, wenn ich diese Aktivität wieder beginne, wird es anfangen, essen 30 MB mehr, und wenn ich zwischen Aktivitäten wie diesem wechseln, wird es schließlich zu OOME führen.

Ich habe in meinen Geräteentwickler-Optionen versucht, "Aktivitäten nicht zu behalten", und es scheint, als würde es mehr RAM freigeben (wie logisch), aber immer noch nicht alles. Ich muss viel mehr wechseln, bevor ich den Speicher verliere, aber das Problem ist immer noch da.

Soll Finish nicht alle in der Aktivität enthaltenen Daten im Garbage Collector ablegen? Ich habe versucht, GC.Collect() zu machen; in meinem OnDestroy, kein Effekt.

Ich weiß nicht, ob ich falsch verstehe, wie Speicher auf Android funktioniert, wie ich ziemlich neu in Mobile Dev bin, aber das gibt mir Kopfschmerzen. Irgendeine Hilfe ?

Danke!

Edit: das ist was ich bekomme, wenn es OOM geht.

05-23 10:15:37.973 D/dalvikvm(5049): GC_FOR_ALLOC freed 1587K, 3% free 248825K/256263K, paused 22ms, total 23ms 
05-23 10:15:37.973 I/dalvikvm-heap(5049): Grow heap (frag case) to 245.840MB for 2908172-byte allocation 
05-23 10:15:38.029 D/dalvikvm(5049): GC_CONCURRENT freed 127K, 2% free 2515 
37K/256263K, paused 10ms+10ms, total 52ms 
05-23 10:15:38.077 D/dalvikvm(5049): GC_FOR_ALLOC freed 74K, 2% free 251463K/256263K, paused 23ms, total 23ms 
05-23 10:15:38.077 I/dalvikvm-heap(5049): Forcing collection of SoftReferences for 11632652-byte allocation 
05-23 10:15:38.105 D/dalvikvm(5049): GC_BEFORE_OOM freed 306K, 2% free 251156K/256263K, paused 29ms, total 29ms 
05-23 10:15:38.105 E/dalvikvm-heap(5049): Out of memory on a 11632652-byte allocation. 
05-23 10:15:38.105 I/dalvikvm(5049): "main" prio=5 tid=1 RUNNABLE 
05-23 10:15:38.105 I/dalvikvm(5049): | group="main" sCount=0 dsCount=0 obj=0xa62704b0 self=0xb7c7b510 
05-23 10:15:38.105 I/dalvikvm(5049): | sysTid=5049 nice=0 sched=0/0 cgrp=[fopen-error:2] handle=-1217084352 
05-23 10:15:38.105 I/dalvikvm(5049): | schedstat=(7886788399 5740305249 19539) utm=596 stm=192 core=0 
05-23 10:15:38.117 E/mono-rt (5049): ================================================================= 
05-23 10:15:38.117 E/mono-rt (5049): Got a SIGSEGV while executing native code. This usually indicates 
05-23 10:15:38.117 E/mono-rt (5049): a fatal error in the mono runtime or one of the native libraries 
05-23 10:15:38.117 E/mono-rt (5049): used by your application. 
05-23 10:15:38.117 E/mono-rt (5049): ================================================================= 
05-23 10:15:38.117 E/mono-rt (5049): 
05-23 10:15:38.117 F/libc (5049): Fatal signal 11 (SIGSEGV) at 0x00000000 (code=1), thread 5049 

Antwort

0

Ok, eine gute Nachricht (Art). Das Problem ist nicht, wo ich zuerst dachte, dass es war. Ich habe dieses Speicherproblem für ein paar Stunden beiseite gelegt und arbeite weiter an den letzten Features der App. Beim Testen meines neuen Codes konnte ich nicht mehr als dreimal zwischen den Aktivitäten navigieren, bevor ich ein OOM erhalte. Ich war wie "warte eine Sekunde, ich könnte stundenlang ohne Fehler wechseln". Also habe ich Git benutzt, um das erste Commit mit diesem Speicherleckproblem zu finden. Und es erschien zuerst mit einer Foto-Upload-Funktion. Mein Speicherverlust ist wahrscheinlich auf einige nicht recycelte Bitmaps zurückzuführen. Es gibt eine Menge Bitmap-Speicherfehler, die auf Stack und anderswo im Internet gefunden werden können, ich sollte es herausfinden können. Danke an alle, die geantwortet haben!

2

Ich schlage vor, Sie diesen Artikel über zu lesen:


Edit:

Probieren Sie etwas wie folgt aus:

using Android.Content; 
using Java.IO; 
using System; 

namespace SampleTest.Droid 
{ 
    public class CacheManager 
    { 
     private static long MaxSize = 5242880L; // 5MB 

     private CacheManager() { } 

     public static void CacheData(Context context, Byte[] data, String name) 
     { 
      try 
      { 
       File cacheDir = context.CacheDir; 
       long size = cacheDir.TotalSpace; 
       long newSize = data.Length + size; 

       if (newSize > MaxSize) 
       { 
        CleanDir(cacheDir, newSize - MaxSize); 
       } 

       File file = new File(cacheDir, name); 
       FileOutputStream OS = new FileOutputStream(file); 

       try 
       { 
        OS.Write(data); 
       } 
       catch (Exception ex) 
       { 
        OS.Flush(); 
        OS.Close(); 
        System.Console.WriteLine(ex.Message); 
        throw; 
       } 
      } 
      catch (IOException ex) 
      { 
       System.Console.WriteLine(ex.Message); 
       throw; 
      } 
     } 

     private static void CleanDir(File dir, long bytes) 
     { 
      long bytesDeleted = 0; 
      File[] files = dir.ListFiles(); 

      foreach (File file in files) 
      { 
       bytesDeleted += file.Length(); 
       file.Delete(); 

       if (bytesDeleted >= bytes) 
        break; 
      } 
     } 

     public static byte[] RetrieveData(Context context, String name) 
     { 
      try 
      { 

       File cacheDir = context.CacheDir; 
       File file = new File(cacheDir, name); 

       if (!file.Exists()) 
       { 
        // Data doesn't exist 
        return null; 
       } 

       byte[] data = new byte[(int)file.Length()]; 
       FileInputStream fis = new FileInputStream(file); 
       try 
       { 
        fis.Read(data); 
       } 
       finally 
       { 
        fis.Close(); 
       } 
       return data; 
      } 

      catch (Exception ex) 
      { 
       System.Console.WriteLine(ex.Message); 
       throw; 
      } 
     } 

     private static long DirSize(File Dir) 
     { 
      long size = 0; 
      File[] files = Dir.ListFiles(); 

      foreach (File file in files) 
      { 
       if (file.IsFile) 
        size += file.Length(); 
      } 
      return size; 
     } 
    } 
} 

Siehe: https://stackoverflow.com/a/10069679/3891036

+0

Ich habe bereits einige davon gelesen, und was ich daraus verstanden habe (vielleicht habe ich mich geirrt), ist, dass wenn eine Aktivität beendet ist, sie im Speicher gehalten wird, um sie schneller neu zu starten, aber wenn wenig Speicher vorhanden ist verfügbar. Aber es scheint nie zu passieren, Speicher geht hoch, bis es die maximale Heap-Größe erreicht. Ich füge ein bisschen von dem Stack-Trace hinzu, den ich habe, als ich diesen OOM bekam. – YumeYume

1

Ersetzen Sie die Aktivitäten mit dem Fragment. Die Aktivitäten sind schwer und ich denke, dass Sie immer wieder neue Aktivitäten in der Navigation machen. Bevor Sie wissen, werden die Dinge leicht außer Kontrolle geraten und Ihre App wird den OOM-Schwellenwert erreichen. Einzelne Aktivität beibehalten und Fragmente darin ersetzen. Hier

ist ein Tutorial über Fragment https://guides.codepath.com/android/Creating-and-Using-Fragments

+0

Ich fing an, Fragmente ein bisschen spät zu benutzen, und es war bereits ein guter Teil der Arbeit mit Aktivitäten erledigt. Ich werde nur eine Aktivität verwenden und nur Fragmente in den nächsten Apps, aber für diese eine, die Arbeit ist zu nah am Ende und die Frist ist in zwei Tagen, so dass ich jetzt nicht wirklich alles ändern kann. Deshalb ich bin auf der Suche nach einer Möglichkeit, diesen seltsamen Speicherverbrauch zu löschen. Aber die Verwendung von Fragmenten ist eine sehr gute Lösung. – YumeYume