Messenger a servizio remoto causando perdite di memory

Ho un'applicazione che comunica con un Service in un process remoto utilizzando l'interface Messenger . Ecco l'architettura di base di come vengono create le cose:

  • L'applicazione genera diversi oggetti "Operation" che richiedono l'accesso al servizio.
  • Ogni "operazione" contiene un Handler avvolto in un Messenger utilizzato per ricevere i dati di risposta dal Service
  • Quando l'operazione viene eseguita, avvolge il suo Messenger in un Intent e chiama startService() per passare il messaggio al servizio remoto
  • Il servizio remoto fa un certo lavoro basato sui parametri dell'intento e quindi restituisce la risposta inviando un Message al Messenger per tale operazione.

Ecco il codice base presente nell'operazione:

  • Visualizzazione della schermata di impostazione solo al primo lancio in android
  • Come eseguire l'applicazione di sistema Android senza root permisson?
  • Android Java; Come posso analizzare un file JSON locale dalla cartella degli asset in un elencoViewView
  • API Google Places Google, getAutocompletePredictions restituisce lo stato 'PLACES_API_ACCESS_NOT_CONFIGURED'
  • dovresti creare nuove attività Async per each chiamata diversa o utilizzare lo stesso
  • Android, JSONObject non può essere convertito in JSONArray
  •  public class SessionOperation { /* ... */ public void runOperation() { Intent serviceIntent = new Intent(SERVICE_ACTION); /* Add some other extras specific to each operation */ serviceIntent.putExtra(Intent.EXTRA_EMAIL, replyMessenger); context.startService(serviceIntent); } private Handler mAckHandler = new Handler() { @Override public void handleMessage(Message msg) { //Process the service's response } }; protected Messenger replyMessenger = new Messenger(mAckHandler); } 

    E uno snippet di come il Servizio è strutturato (è fondamentalmente un IntentService che non si chiude quando la coda è vuota):

     public class WorkService extends Service { private ServiceHandler mServiceHandler; private final class ServiceHandler extends Handler { public ServiceHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { onHandleIntent((Intent)msg.obj); } } @Override public int onStartCommand(Intent intent, int flags, int startId) { //If intent has a message, queue it up Message msg = mServiceHandler.obtainMessage(); msg.obj = intent; mServiceHandler.sendMessage(msg); return START_STICKY; } private void onHandleIntent(Intent intent) { Messenger replyTarget = intent.getParcelableExtra(Intent.EXTRA_EMAIL); /* Do some work */ Message delivery = Message.obtain(...); replyTarget.send(delivery); } } 

    Tutto questo funziona fantasticamente bene. Posso submit tonnellate di operazioni da diverse applicazioni diverse allo stesso servizio e tutti elaborano e inviano la loro risposta al giusto posto. Però…

    Ho notato che se l'applicazione è stata eseguita abbastanza a lungo e con abbastanza attività sarebbe crash con un OutOfMemoryError . Dopo aver esaminato i dati HPROF in MAT, ho notato che tutte queste operazioni rimangono in memory e sono state detenute in ostaggio dal Garbage Collector a causa del Messenger . A quanto pare, l'istanza Messenger crea una connessione nativa a Binder, che conta come una radice di GC, che tiene in memory l'object di "Operation" in modo indefinito.

    Esempio di traccia MAT

    Qualcuno sa se c'è un modo per cancellare o distriggersre il Messenger quando l'operazione è finita per non creare questa perdita di memory? C'è forse un altro modo per implementare l'IPC al Service nello stesso modo in modo che più oggetti disparati possano fare una richiesta e get un risultato in modo asincrono?

    Grazie in anticipo!

  • React Native & okhttp su Android - Imposta User-Agent
  • Clausola IN e segnaposto
  • cordova inappbrowser e file di input
  • Errore di dialogo di login di Twitter
  • Come accedere a facebook utilizzando sdk 4.1.0 in android?
  • Elenca tutti i file da tutta la cartella in un singolo elenco
  • 2 Solutions collect form web for “Messenger a servizio remoto causando perdite di memory”

    Grazie a una visione molto utile di Dianne Hackborn sul team Android, il problema è dovuto al fatto che il process di servizio remoto non ha ancora recuperato Garbage è l'istanza del Messenger che, in effetti, ha mantenuto gli istanze nel process dell'applicazione in ostaggio fino a quel momento.

    Questo è il text della sua risposta:

    È vero che l'invio di un messaggero attraverso i processi richiederà di tenere un GREF su di esso per l'altro process di comunicare con esso. Barriere di blocchi (che sono accaduti, ma non sono sicuro se in qualsiasi versione di piattaforma rilasciata), il GREF verrà rilasciato quando l'altro process stesso non ha più alcun riferimento su questo. Quando parliamo di cose in Dalvik "non ha più alcun riferimento" generalmente significa "l'altro lato ha rifiuti raccolti l'object proxy Java".

    Ciò significa che quando si lancia un messaggero (o qualsiasi object IBinder) in un altro process, il Dalvik VM nel proprio process non può più gestire la memory di quell'object stesso e dipende da tutti gli oggetti remoti che lo rilasciano finché non può essere rilasciati localmente. E questo include tutti gli oggetti che IBinder ha anche riferimenti.

    Un model comune per far fronte a questo è utilizzare un WeakReference nel tuo IBinder / Messenger che contiene i riferimenti al resto degli oggetti che accederà. Ciò consente al vostro collettore di rifiuti locale di ripulire tutti gli altri oggetti (che possono essere abbastanza pesanti, tenendo grandi cose come bitmap e simili) anche se un process remoto ha ancora un riferimento sul tuo IBinder. Naturalmente se lo fai, c'è bisogno di essere qualcos'altro che detiene un riferimento su questi altri oggetti finché non sono più necessari, altrimenti il ​​collettore di rifiuti potrebbe pulirli prima che non siano più necessari.

    Un'altra cosa che vorrei raccomandare è di non fare un disegno where si istanzia gli oggetti Messenger per each IPC che fai. Crea un messaggero che passa a each chiamata IPC. Altrimenti è ansible generare molti oggetti remotati che vengono mantenuti in giro per altri processi che continuano a tenere i riferimenti perché l'altro lato non è aggressivamente la raccolta di rifiuti perché tutti gli oggetti che sta creando a causa di queste chiamate sono piccole.

    Ulteriori informazioni: https://groups.google.com/d/msg/android-developers/aK2o1W2xrMU/Z0-QujnU3wUJ

    Non sono sicuro se questo è il modo migliore perché, anche se l' Activity è in background, riceverai il message dal Service .

    Penso che dovresti bind al service e registrare un messenger al servizio non appena il servizio è connesso. E poi annullare la logging del messenger quando si scollega.

    Controllare ExportVcardActivity in AOSP. Sta seguendo qualcosa in queste linee.

    L'Android è un fan Android di Google, tutto su telefoni Android, Android Wear, Android Dev e applicazioni Android Games e così via.