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 Handler wrapped in a Messenger used as a
callback receive the response data back from the Service
- When the operation executes, it wraps its Messenger into an Intent and
calls startService() to pass the message to the remote service
- The remote service does some work based on the parameters of the Intent
and
then returns the response by sending a Message to the Messenger for 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.
[image: MAT Trace Example]
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 [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/android-developers?hl=en