1

我最近遇到了一个奇怪的内存问题。每次我启动 MyActivity(它启动 MyService)时,我的应用程序的内存使用量都会增加。因此,在启动和完成 MyActivity 几次后,我的应用程序内存不足。在启动和完成 MyActivity 两次后,我进行了堆转储。我发现内存中有 2 个 MyService 实例。在我执行“传入引用”->“gc 根路径”之后,我得到了以下行(在两个实例上):

com .....MyService @ 0x42746880

->this$0 com.....MyService$MyServiceBinder @42746928 本机堆栈

我的代码与此类似:

public class MyService extends Service {

    ...

    public class MyServiceBinder extends Binder{
        MyService getService(){
            return MyService.this;
        }
    }

}

public class MyActivity extends Activity{

    private MyService service;

    ...

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        launchService(savedInstanceState==null); //start MyService
    }

    ...

    @Override
    protected void onStart(){
        super.onStart();
        if(clientService == null)
            getApplicationContext().bindService(new Intent(this, MyService.class), connection, Context.BIND_NOT_FOREGROUND);
    }

    @Override
    protected void onStop(){
        super.onStop();
        if(clientService != null)
            getApplicationContext().unbindService(connection);
    }

    @Override
    protected void onDestroy(){
        super.onDestroy();
    }

    @Override
    protected void onBackPressed(){
        service.destroyService();  //stops MyService ->calls stopSelf inside MyService
        finish();
    }

private LocalServiceConnection connection = new LocalServiceConnection(this);

private static class LocalServiceConnection implements ServiceConnection{

        private final WeakReference<MyActivity> parent;

        private MyActivity activity;

        private MyServiceBinder binder;

public LocalServiceConnection(MyActivity parent){
    this.parent = new WeakReference<MyActivity>(parent);
        }

@Override
public void onServiceConnected(ComponentName arg0, IBinder arg1) {
            activity = parent.get();
            if(activity==null)
                return;
            binder = (MyServiceBinder) arg1;
            activity.service = binder.getService();
            ...
            activity = null;

        }

        @Override
        public void onServiceDisconnected(ComponentName arg0) {
            activity = parent.get();
            binder = null;
            if(activity==null)
                return;
            activity.service = null;
            activity = null;
        }

    }
}

我不确定 MyServiceBinder 中对 MyService 的引用是否是泄漏的来源。那么我的代码中可能存在泄漏吗?

谢谢和问候

编辑:

private void launchService(boolean isFirst){
    if(service == null){
        if(isFirst)
            startService(new Intent(this, MyService.class);
    }
}

如果我“通常”关闭 MyActivity 服务将停止,因此 onServiceDisconnect 在 onDestroy -> unbindService 未被调用之前被调用

编辑2:

我再次进行了一些堆转储并通过 ddms 强制 GC(导致 GC)。我发现 MyService、MyServiceBinder 和 LocalServiceConnection 无法进行垃圾收集,因为它们仍然保留在内存中,而所有其他实例都已被释放。MyService 和 LocalServiceConnection 具有对 MyServiceBinder 对象的动态引用。MyServiceBinder 似乎没有通往 gc 根的路径。问题是为什么这个 Binder 对象没有被垃圾收集???会不会是 MyServiceBinder 引用了 MyService,而后者又引用了 MyServiceBinder?也许-如果确实存在这种循环-因此无法释放 MyServiceBinder 对象?

4

4 回答 4

2

因此,我将 Binder 类设置为一个独立的类,并带有对服务的弱引用。这并没有解决活页夹和服务连接对象的问题(它们仍然没有被垃圾收集),但是“巨大的”服务对象被收集了..

于 2013-08-30T16:47:52.107 回答
1

确保您在 onPause 方法中取消绑定服务:

绑定服务:

 @Override
  protected void onResume() {
    super.onResume();
    bindService();
  }

取消绑定服务

 @Override
  protected void onPause() {
    super.onPause();
    unbindService();
  }
于 2013-08-18T13:24:35.193 回答
0

在您的onCreate()检查服务中以这种方式检查 null 然后调用launchService()

if (service == null){
   launchService();
} 

在你onDestroy()做同样的事情;检查它是否不为空,然后调用destroyService()

if (service !=null){
    destroyService();
}
于 2013-08-18T13:23:13.393 回答
0

我看到您的服务被标记为private,您是否有任何服务获取方法以使其可用于其他类?如果你这样做了,你应该检查你在哪里使用 getter 方法。如果另一个类保留对服务的引用,它将不会被 gc'd。Android 中的一个大问题是将Activity周围的引用传递给其他类。如果你这样做,并且另一个类持有对 的引用Activity,它就不会被 gc'd。而且由于看起来服务、活页夹和 LocalServiceConnection 都保存在您的中,因此如果未释放Activity对 的引用,它们都不会被 gc 处理。Activity

于 2013-08-30T19:58:16.797 回答