I have an application that communicates with a Service in a remote process using the Messengerinterface. Here is the basic architecture of how things are set up:
- The application generates several "Operation" objects that require access to the service.
- Each "Operation" contains a
Handlerwrapped in aMessengerused as a callback receive the response data back from theService - When the operation executes, it wraps its
Messengerinto anIntentand callsstartService()to pass the message to the remote service - The remote service does some work based on the parameters of the
Intentand then returns the response by sending aMessageto theMessengerfor that operation.
Here is the basic code present in the operation:
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);
}
And a basic snippet of how the service is structured:
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);
}
}This all works fantastically well. I can send tons of operations from several different applications to the same service and they all process and send their response to just the right place. However...
I noticed that if the application ran long enough and with enough activity it would crash with anOutOfMemoryError. Upon looking at the HPROF data in MAT, I noticed that all these operations where staying in memory, and they were held hostage from the Garbage Collector because of theMessenger. Apparently, the Messenger instance is creating a long-term native connection to Binder that counts as a GC Root, which is keeping each "Operation" object in memory indefinitely.

Does anyone know if there is a way to clear or disable the Messenger when the "Operation" is over so it doesn't create this memory leak?
Is there perhaps a better way to implement the IPC to the Servicein the same fashion, so that multiple disparate objects can make a request and get a result asynchronously? I'm not convinced that just switching to using a bound service implementation will solve this issue as I would will need the Messenger to process the callback.
You received this message because you are subscribed to the Google
Groups "Android Developers" group.
To post to this group, send email to android-developers@googlegroups.com
To unsubscribe from this group, send email to
android-developers+unsubscribe@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/android-developers?hl=en
No comments:
Post a Comment