Dev*_*red 2 service android memory-leaks
我有一个应用Service程序使用该Messenger接口与远程进程通信.以下是设置方式的基本架构:
Handler包装MessengerServiceMessenger成Intent并调用startService()以将消息传递给远程服务Intent,然后通过发送Message给该Messenger操作来返回响应.以下是操作中的基本代码:
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);
}
Run Code Online (Sandbox Code Playgroud)
以及如何构建服务的片段(IntentService当队列为空时,它基本上不会关闭):
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);
}
}
Run Code Online (Sandbox Code Playgroud)
这一切都非常好.我可以将来自多个不同应用程序的大量操作发送到同一个服务,他们都会处理并将响应发送到正确的位置.然而...
我注意到如果应用程序运行得足够长并且有足够的活动,它会崩溃OutOfMemoryError.在MAT中查看HPROF数据时,我注意到所有这些操作都停留在内存中,并且由于这些操作而被垃圾收集器挟持Messenger.显然,该Messenger实例正在创建一个与Binder的长期本机连接,它被视为GC Root,它将每个"Operation"对象无限期地保存在内存中.

有没有人知道是否有办法清除或禁用Messenger"操作"结束时,所以它不会创建此内存泄漏?是否有另一种方法可以以Service相同的方式实现IPC ,以便多个不同的对象可以发出请求并异步获得结果?
提前致谢!
Dev*_*red 11
感谢Dianne Hackborn在Android团队中提供的一些非常有用的见解,问题是因为远程服务进程还没有Garbage收集它的Messenger实例,实际上,直到那个时候,实例才将实例保存在应用程序的进程中.
这是她回复的内容:
确实,跨进程发送信使需要在其上持有GREF,以便其他进程与之通信.除了错误(已发生但我不确定是否在任何已发布的平台版本中),当其他进程本身不再对此进行引用时,GREF将被释放.当我们在Dalvik谈论事情时"不再持有引用"通常意味着"另一方有垃圾收集了Java代理对象".
这意味着当您将Messenger(或任何IBinder对象)传递到另一个进程时,您自己进程中的Dalvik VM无法再管理该对象本身的内存,并依赖于释放它的所有远程对象,直到它可以在当地发布.这将包括IBinder所有引用的所有对象.
处理此问题的常见模式是在IBinder/Messenger中使用WeakReference,其中包含对将要访问的其他对象的引用.这允许您的本地垃圾收集器清理所有其他对象(可能非常重,包含诸如位图之类的大事件),即使远程进程仍然在您的IBinder上有引用.当然,如果你这样做,就需要有其他东西在这些其他对象上不再需要它们,或者垃圾收集器可以在它们不再需要之前清理它们.
我建议的其他方法是不进行设计,为每个IPC实例化Messenger对象.创建一个传递给每个IPC调用的Messenger.否则,您可以生成许多远程保留的远程对象,因为其他进程继续保留引用,因为另一方没有积极地进行垃圾回收,因为由于这些调用而创建的所有对象都很小.
更多信息:https: //groups.google.com/d/msg/android-developers/aK2o1W2xrMU/Z0-QujnU3wUJ
| 归档时间: |
|
| 查看次数: |
1596 次 |
| 最近记录: |