2016-07-01 7 views
1

ich ein Android-Dienst haben, die eine Benachrichtigung aktualisiert jede Sekunde dieses Thema mit (Kommentare sind nicht wirklich relevant):Android und Java: Speichernutzung auf einer Serviceschleife reduzieren

thread = new Thread() { 
    @Override 
    public void run() { 
     // Preparando la notificación de Swap 
     NotificationCompat.Builder notificationSwap = 
       new NotificationCompat.Builder(context) 
         .setSmallIcon(android.R.drawable.ic_dialog_info) 
         .setContentTitle("Notificator:"); 
     NotificationManager notificationManager = 
       (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); 
     int notificationSwapId = 1; // TODO: Asignar un ID que no sea "Magic number" 

     while (!stop) { 
      String swapInfo = null; 

      try{ // TODO: free devuelve siempre 4 líneas? 
       Process free = Runtime.getRuntime().exec("free"); 
       BufferedReader freeOut = 
         new BufferedReader(
           new InputStreamReader(new DataInputStream(free.getInputStream()))); 
       free.waitFor(); 
       freeOut.readLine(); 
       freeOut.readLine(); 
       freeOut.readLine(); 
       swapInfo = freeOut.readLine(); 
      }catch(Exception e){ 
       Log.e("ERROR", e.toString()); // TODO: Mejorar esto 
      } 
      Scanner scanner = new Scanner(swapInfo); // TODO: Mejorar esto 
      String swapInfo2 = null; 
      if (scanner.hasNext()) { 
       scanner.skip("Swap:"); 
      } 
      if (scanner.hasNextInt()) { 
       /*swapInfo2 = "Total: " + */scanner.nextInt(); 
      } 
      if (scanner.hasNextInt()) { 
       swapInfo2 = "Usado: " + scanner.nextInt(); 
      } 
      if (scanner.hasNextInt()) { 
       swapInfo2 += "\nLibre: " + scanner.nextInt(); 
      } 

      // Notificando 
      notificationSwap.setContentText(swapInfo2); 
      notificationManager.notify(notificationSwapId, notificationSwap.build()); 

      // Intentando liberar memoria 
      //System.gc(); 

      try { 
       Thread.sleep(new Integer(PreferenceManager.getDefaultSharedPreferences(context).getString("frecuency", "60000"))); // TODO: Mejorar esto 
      } catch (InterruptedException e){ 
       Log.d("Notificator (Service)", "Deteniendo el hilo durante la espera"); // TODO: Mejorar esto 
       // TODO: ¿Qué pasa si el hilo es interrumpido fuera del try/catch? Si pilla la interrupción no hace falta la variable stop 
      } 
     } 
    } 
}; 

Das Problem ist, dass es über verwendet 20 MB Speicher, aber wenn ich die "//System.gc();" Linie diese Zahl sinkt auf ca. 3/4MB, das ist eine Menge Müll. Aber wenn ich den gesamten Garbage Collector in jeder Schleife abspiele, scheint das für mich nicht sehr effizient zu sein und die CPU-Auslastung steigt.

Das ist der Grund, warum ich Müllsammler nicht mag, in einer C++ Schleife nur mit Hilfe von Autovariablen hätte ich dieses Problem nicht, aber ich denke, das könnte besser gemacht werden, da ich weder wirklich zu Java noch Android.

Meine Hauptfrage ist also, wie kann ich den Speicherverbrauch auf eine effizientere Weise senken? Ich würde mir auch bessere Möglichkeiten vorstellen, um eine Benachrichtigung auf Android zu verbessern, aber was ich wirklich brauche, ist zu verhindern, dass diese Art von Code so viel Speicher verbraucht.

UPDATE:

Antworten sind darauf hindeutet, dass ich den Strom schließen sollte, die Scanner, etc., ich bin nicht wirklich sicher, ob dies necesary ist oder nicht (Schließen des Stroms und der Scanner löst nicht die Problem), aber ich denke, das ist nicht das Problem, da sie sowieso erfolgreich gelöscht werden.

Das Problem ist, dass sie häufen sich vor dem Löschen und ich möchte sie löschen, bevor der Thread schläft statt auf den Garbage Collector zu warten, und da das nicht in Java getan werden kann, soweit ich weiß, brauche ich eine mehr "Garbage Collector Friendly" -Approach.

Antwort

0

In finally-Block können Sie das Folgende tun

finally { 
try { 
    freeOut.close(); 
} catch (IOException e) { 
    e.printStackTrace(); 
} 
+0

Sie können auch die Zeile 'scanner.close()' hinter 'freeOut.close()' einfügen. Hauptproblem hier ist, dass Sie einen neuen BufferedReader und einen neuen Scanner für jeden Lauf in der While-Schleife erstellen und Sie nie schließen, daher die große Speicherauslastung. –

+0

Danke, aber die Objekte werden gelöscht, so dass das nicht das Problem ist. – JotaGe

0

wie kann ich die Speichernutzung in einer eficient Weise senken?

Die große Sache wäre, all diesen Prozess-Forking-Unsinn loszuwerden und es durch a simple call to getMemoryInfo() zu ersetzen. Oder verwenden Sie JNI, um einige C-APIs aufzurufen, um Ihre Speicherinformationen abzurufen. Einen Prozess jede Sekunde anzuzweigen, ist auf einem mobilen Gerät äußerst verschwenderisch. Außerdem haben Sie keine Möglichkeit zu wissen, ob auf jedem Gerät free vorhanden ist, da die bidirektionalen On-Device-Befehlszeilenprogramme nicht Teil des Android SDK sind und nicht garantiert konsistent sind.

Verwenden Sie in zweiter Linie StringBuilder oder String.format() statt String Verkettung, um Ihre Notification Text aufzubauen.

+0

Über getMemoryInfo(): Ich möchte kostenlos verwenden, in der Tat möchte ich einen benutzerdefinierten Befehl oder ein Skript ausführen, verwende ich kostenlos zum Testen, da dies mein erster Service ist. Über StringBuilder: Ich sollte es wahrscheinlich verwenden. Aber es löst immer noch nicht das Hauptproblem: unbenutzte Objekte. Ich denke, es sollte einen Weg geben, die JVM (oder Dalvik) wissen zu lassen, dass diese Objekte am Ende der Schleife gelöscht werden sollten, damit sie sie effizient löschen können ... – JotaGe

+0

@JotaGe: "Ich möchte kostenlos verwenden" - dann beschweren Sie sich nicht über den Speicherverbrauch und beschweren Sie sich nicht über die Kompatibilität."Ich denke, es sollte einen Weg geben, die JVM (oder Dalvik) wissen zu lassen, dass diese Objekte am Ende der Schleife gelöscht werden sollten, damit sie sie effizient löschen können" - das wird schon für Sie erledigt. GC ist nicht aggressiv, bis es erforderlich ist (z. B. "OutOfMemoryError" zu vermeiden), und bevorzugt es, bis zu mehr Leerlaufperioden zu warten. Ihr A-Prozess-alle-Sekunden-Ansatz wird hier nicht helfen. – CommonsWare

+0

Ich glaube, du hast kein Recht, mir zu sagen, ob ich mich über etwas beschweren muss oder nicht. Hier ist eine mehr auf den Punkt Frage ohne Prozesse beteiligt, trotzdem: http://stackoverflow.com/questions/38171211/how-should-i-create-objecs-inside-a-loop-whithout-wasting-memory – JotaGe