2013-08-18 4 views
0

나는 최근에 이상한 기억 문제에 부딪쳤다. MyActivity (MyService를 시작 함)를 시작할 때마다 내 앱의 메모리 사용량이 증가합니다. 그래서 MyActivity를 시작하고 끝내고 나서 몇 시간 후에 앱의 메모리가 부족합니다. MyActivity를 두 번 끝내고 마무리 한 후에 힙 덤프를 수행했습니다. 나는 거기에 MyService의 2 인스턴스가 메모리에 있음을 발견했다. >이 $ 0 - 0x42746880Android 서비스 바인더가 누출 되었습니까?

@

COM .....이면 MyService : - 내가 '수신 참조'한 후 '뿌리를 GC하는 경로'> 나는 (두 경우에) 라인을 다음 있어요 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에 대한 참조가 누출의 원인인지 확실하지 않습니다. 그래서 내 코드에 누수가있을 수 있습니까?

들으 & reagards

편집 :

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

내가 "보통"가까운 MyActivity이 서비스가 중지되고, 따라서 onServiceDisconnect이들의 OnDestroy 전에 호출되는 경우 -> unbindService이

EDIT2 호출되지 않습니다 :

일부 힙 덤프를 다시 작성하고 ddms를 통해 GC를 강제 실행했습니다 (GC 발생). MyService, MyServiceBinder 및 LocalServiceConnection은 가비지 수집을 할 수 없다는 것을 알았습니다. 다른 모든 인스턴스가 해제 된 동안 여전히 메모리에 남아 있기 때문입니다. MyService 및 LocalServiceConnection에는 MyServiceBinder 객체에 대한 실제 참조가 있습니다. MyServiceBinder는 gc 루트에 대한 경로가없는 것 같습니다. 문제는이 바인더 객체가 가비지 수집되지 않는 이유입니다. ??? MyServiceBinder가 MyService를 참조하고 MyServiceBinder가 MyServiceBinder를 참조 할 수 있습니까? 어쩌면 - 그런 종류의 루프가 존재한다면 - MyServiceBinder 객체는 해제 될 수 없습니까? 널 (null)에 대한 onCreate() 검사 서비스에서

+0

launchService() 구현? –

+0

방금 ​​코드를 업데이트하여보다 정확하게 만들었습니다. – user2224350

답변

1

그래서 나는 바인더 클래스를 약점을 가진 독립형 클래스로 만들었습니다.그 바인더 및 serviceConnection- 개체 (그들은 여전히 ​​가비지 수집 얻을지 않습니다) 문제를 해결하지 못했지만 "거대한"서비스 개체가 수집 가져옵니다.

+0

문제의 실제 해결책이 아닌 해결 방법입니다 ... 동일한 솔루션을 사용 했으므로 서비스 누출을 피하는 것이 효율적이라는 것이 입증되었습니다. –

0

이 방법과는 launchService()

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

과에 전화하여 onDestroy() 동일한 작업을 수행; null가 아닌 있는지 확인한 후 전화 destroyService() :

바인드 서비스 :

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

바인딩을 해제 서비스

if (service !=null){ 
    destroyService(); 
} 
0

유 onPause 방법에서 서비스 바인딩을 해제해야합니다 :

@Override 
    protected void onPause() { 
    super.onPause(); 
    unbindService(); 
    } 
+0

getApplicationContext(). unbindService()를 호출하지 않고 서비스가 중지되면 onServiceConnection이 호출됩니다. 그게 누출을 일으킬 수 있습니까? – user2224350

+0

onServiceConnection은 서비스에 바인딩 된 경우에만 호출됩니다. –

+0

죄송합니다. 죄송합니다. onServiceDisconnected를 의미했습니다. – user2224350

0

나는 귀하의 서비스가 private , 다른 클래스에서 사용할 수 있도록하는 getter 메소드가 있습니까? 그렇게 할 경우 getter 메소드를 사용하는 곳을 확인해야합니다. 다른 클래스가 서비스에 대한 참조를 유지한다면 그것은 얻을 수 없을 것입니다. Android의 큰 문제는 Activity이라는 참조를 다른 클래스로 전달하는 것입니다. 이 작업을 수행하고 다른 클래스가 Activity에 대한 참조를 보유하면 gc'd가되지 않습니다. 그리고 서비스처럼 보이기 때문에, 바인더와 LocalServiceConnection은 Activity 안에 있고, Activity에 대한 참조가 해제되지 않은 경우 gc 될 것입니다.

관련 문제