使者远程服务导致内存泄漏 [英] Messenger to Remote Service Causing Memory Leak

查看:148
本文介绍了使者远程服务导致内存泄漏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个服务在一个偏僻的过程中使用了使者接口进行通信的应用程序。下面是事情是如何设置的基本结构:

I have an application that communicates with a Service in a remote process using the Messenger interface. Here is the basic architecture of how things are set up:

  • 应用程序生成需要访问服务的几个操作的对象。
  • 在每个操作包含了一个处理程序裹在使者用于接收响应数据返回从服务
  • 当操作执行,它包裹了使者意图键,通话 startService ()把消息传递给远程服务
  • 在远程服务确实根据意图的参数的一些工作,然后通过发送消息到使者该操作。
  • The application generates several "Operation" objects that require access to the service.
  • Each "Operation" contains a Handler wrapped in a Messenger used to 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.

下面是基本的code present的操作:

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);
}

和如何服务的结构片段(这基本上是一个 IntentService 不关机,当队列为空):

And a snippet of how the Service is structured (it's basically an IntentService that doesn't shut down when the queue is empty):

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...

我注意到,如果应用程序运行足够长的时间和足够的活动也将崩溃与的OutOfMemoryError 。当看着在MAT的HPROF数据,我注意到,所有这些操作在那里停留在内存中,他们因为使者的挟持的垃圾收集器。显然,使者实例被创建到活页夹一个长期的本地连接,则计为一个GC根,这是保持每一个操作的对象在内存下去。

I noticed that if the application ran long enough and with enough activity it would crash with an OutOfMemoryError. 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 the Messenger. 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 another way to implement the IPC to the Service in the same fashion, so that multiple disparate objects can make a request and get a result asynchronously?

在此先感谢!

推荐答案

由于一些来自戴安娜Hackborn在Android团队非常有益的见解,这个问题是因为远程服务进程尚未垃圾回收它的信使的实例,实际上,举行了在应用程序的过程中人质的情况下,到那个时候。

Thanks to some very helpful insight from Dianne Hackborn on the Android team, the issue is because the remote service process has not yet Garbage Collected it's instance of the Messenger which, in effect, held the instances in the application's process hostage until that time.

这是她的答复的文本:

这是事实,在进程发送一个信使将需要持有它GREF为其他进程与之通信。除非错误(发生这,但我不知道,如果在任何发布平台的版本),该GREF会当其它程序本身不再持有该基准被释放。当我们在谈论的事情的Dalvik不再持有一个引用通常是指对方已垃圾回收Java代理对象。

It is true that sending a messenger across processes will require holding a GREF on it for the other process to communicate with it. Barring bugs (which have happened but I am not sure if in any released platform versions), the GREF will be released when the other process itself no longer holds a reference on this. When we are talking about things in Dalvik "no longer holds a reference" generally means "the other side has garbage collected the Java proxy object."

这句话的意思是,当你跨越到另一个进程抛出一个信使(或任何的IBinder对象),Dalvik虚拟机在自己的过程中可以不再管理该对象本身的内存,并且依赖于所有的远程对象释放它直到它可以局部地释放。这将包括在的IBinder有任何引用,以及所有的对象。

What this means is that when you throw a Messenger (or any IBinder object) across to another process, the Dalvik VM in your own process can no longer manage the memory of that object itself and is dependent on all remote objects releasing it until it can be released locally. And this will include all objects that the IBinder has any references to as well.

一个常见的​​模式来处理这个是用在你的IBinder /斜挎一个WeakReference的持有引用到你的对象的其余部分,它会访问。这使得当地的垃圾收集器来清理所有其他对象(这可能是相当沉重的,抱着像位图和这么大的事情),即使远程进程仍然对你的IBinder参考。当然,如果你做到这一点,需要有别的东西持有这些对象的引用,直到他们不再需要的,否则之前的,他们不再需要在垃圾收集器可以清除它们的

A common pattern to deal with this is to use a WeakReference in your IBinder/Messenger that holds the references to the rest of your objects that it will access. This allows your local garbage collector to clean up all of those other objects (which may be quite heavy, holding big things like bitmaps and such) even though a remote process still has a reference on your IBinder. Of course if you do this, there needs to be something else holding a reference on these other objects until they are no longer needed, or else the garbage collector could clean them up before they are no longer needed.

别的东西,我会建议是不要做你实例Messenger的对象,你每做工控机的设计。创建您传递给每一个IPC的一个电话使者。否则,您可以产生大量的被关押各地因其他进程继续持有引用远程对象,因为对方不是积极,因为所有正在创建由于这些电话都是小物件垃圾回收。

Something else I would recommend is to not do a design where you instantiate Messenger objects for each IPC you do. Create one Messenger that you pass in to each IPC call. Otherwise you can generate a lot of remoted objects that are being kept around due to other processes continuing to hold references because the other side is not aggressively garbage collecting since all the objects it is creating due to these calls are small.

更多信息: https://groups.google.com/d/msg/android -developers / aK2o1W2xrMU / Z0-QujnU3wUJ

这篇关于使者远程服务导致内存泄漏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆