2011-06-18 14 views
2

私は、アプリケーションの重大なメモリリークの問題を特定し、アクティビティがすぐに作成/破棄されたときに(またはおそらくはすぐに再開/一時停止するときに)私はテストに基づいて考えているもの)。メモリリーク管理サービスの接続onアクティビティonResume/onPause

私は、これを引き起こしていることとそれを正しく修正する方法を理解するのに役立つと思います。 これは、別のアプリから別のアプリに切り替わり、画面の向きが違う(接続オブジェクトを保持している自分のアクティビティがフォアグラウンドにない)場合に発生します。

GCルートの 'LoadedApk $ ServiceDispatcher $ DeathMonitor'オブジェクトによって参照されているように見えるため、ガベージコレクションの対象にならないようなアクティビティがあります。

私はonResume()でbindを呼び出し、onPause()でunBindを呼び出します。 いくつかの実験をした後、問題の根本原因を何とかバインド/アンバインドする方法を信じています。例えば、私がバインドを解除すると、メモリリークは止まりますが、ConnectionLeakedの例外がいくつか発生します(原因はわかります)。 接続オブジェクトが通知を受け取る前にunbindを呼び出していると、何らかの理由でこの問題が発生しています(ただし、logcatでエラーが表示されず、サービスがbind/unbind呼び出しを適切に受け取ります)。 (私は前後に私のアプリと他のアプリとの間に数回を切り替えた後)私はEclipseのメモリアナライザを使用する場合

私はGCルートへの次のパスで活動インスタンスの束を参照してください。

MyActivityを

< --mContext android.app.LoadedApk $ ServiceDispatcher @

< 0x41059d6 ----この$ 0 android.app.LoadedApk $ ServiceDispatcher $ DeathMonitor @ネイティブスタック0x4105b548

私のソースコードは、基本的には、次のとおりです。

public class MyActivity extends Activity { 
    private final String TAG = "MyActivity"; 
    public IREventService mREventService; 
    private ServiceConnection mConnection = new ServiceConnection() { 
     // Called when the connection with the service is established 
     public void onServiceConnected(ComponentName className, IBinder service) { 
      mREventService = IREventService.Stub.asInterface(service); 
      Log.e(TAG, "connected to service:"+MyActivity.this.toString()+ "connection: "+this.toString()); 

     } 

     // Called when the connection with the service disconnects unexpectedly 
     public void onServiceDisconnected(ComponentName className) { 
      Log.e(TAG, "Service has unexpectedly disconnected:"+this.toString()); 
      mREventService = null; 
     } 
    }; 

    @Override 
    protected void onResume() { 
     super.onResume(); 
     Intent intent = new Intent(this, EventService.class); 
     intent.setAction(this.toString()); 

     Log.w(TAG, "bindService:"+this.toString()); 
     bindService(intent, 
       mConnection, Context.BIND_AUTO_CREATE); 
    } 


    @Override 
    protected void onPause() { 
     super.onPause(); 
     Log.w(TAG, "unbinding from service:"+this.toString()); 
     unbindService(mConnection); 

    } 


} 

logcatsログは次のようになります。助けを

<I switched to another app> 
06-17 17:27:08.965: WARN/MyActivity(5987): MyActivity onStop() 

<this is where i switch back to my app> 
06-17 17:27:09.415: INFO/ActivityManager(154): Config changed: { scale=1.0 imsi=310/4 loc=en_US touch=3 keys=1/1/2 nav=1/2 orien=L layout=0x10000014 uiMode=0x11 seq=169} 
06-17 17:29:44.855: WARN/MyActivity(5987): MyActivity onDestroy() 
06-17 17:29:44.855: INFO/TabletStatusBar(205): DISABLE_BACK: no 
06-17 17:29:45.015: WARN/MyActivity(5987): MyActivity onCreate() 
06-17 17:29:45.015: WARN/MyActivity(5987): MyActivity onResume() 
06-17 17:29:45.015: WARN/MyActivity(5987): bindService:[email protected] 
06-17 17:29:45.015: WARN/EventService(6009): onBind() [email protected] 
06-17 17:29:45.025: WARN/MyActivity(5987): MyActivity onPause() 
06-17 17:29:45.025: WARN/MyActivity(5987): unbinding from service:[email protected] 
06-17 17:29:45.025: WARN/EventService(6009): onUnBind() [email protected] 
06-17 17:29:45.025: ERROR/MyActivity(5987): connected to service:[email protected]: [email protected] 
06-17 17:29:45.065: DEBUG/dalvikvm(5987): GC_FOR_ALLOC freed 32K, 3% free 31936K/32839K, paused 34ms 
06-17 17:29:45.125: DEBUG/dalvikvm(5987): GC_FOR_ALLOC freed 65K, 4% free 32895K/33927K, paused 36ms 
06-17 17:29:45.205: DEBUG/dalvikvm(5987): GC_FOR_ALLOC freed 803K, 5% free 33550K/35079K, paused 30ms 
06-17 17:29:45.245: DEBUG/dalvikvm(5987): GC_FOR_ALLOC freed 65K, 4% free 34109K/35335K, paused 27ms 
06-17 17:29:45.255: INFO/dalvikvm-heap(5987): Grow heap (frag case) to 36.976MB for 3722256-byte allocation 
06-17 17:29:45.285: DEBUG/dalvikvm(5987): GC_FOR_ALLOC freed <1K, 4% free 37744K/38983K, paused 25ms 
06-17 17:29:45.335: DEBUG/dalvikvm(5987): GC_CONCURRENT freed <1K, 4% free 37744K/38983K, paused 2ms+3ms 
06-17 17:29:45.645: INFO/WindowManager(154): Setting rotation to 3, animFlags=1 
06-17 17:29:45.665: INFO/ActivityManager(154): Config changed: { scale=1.0 imsi=310/4 loc=en_US touch=3 keys=1/1/2 nav=1/2 orien=P layout=0x10000014 uiMode=0x11 seq=170} 
06-17 17:29:45.685: DEBUG/FlurryAgent(5770): Ending session 
06-17 17:29:45.755: WARN/MyActivity(5987): MyActivity onStop() 
06-17 17:29:45.755: WARN/MyActivity(5987): MyActivity onDestroy() 
06-17 17:29:45.755: WARN/IInputConnectionWrapper(5770): showStatusIcon on inactive InputConnection 
06-17 17:29:45.865: WARN/MyActivity(5987): MyActivity onCreate() 
06-17 17:29:45.865: WARN/MyActivity(5987): MyActivity onResume() 
06-17 17:29:45.865: WARN/MyActivity(5987): bindService:[email protected] 
06-17 17:29:45.875: WARN/EventService(6009): onBind() [email protected] 
06-17 17:29:45.875: WARN/MyActivity(5987): MyActivity onPause() 
06-17 17:29:45.875: WARN/MyActivity(5987): unbinding from service:[email protected] 
06-17 17:29:45.875: WARN/EventService(6009): onUnBind() [email protected] 
06-17 17:29:45.875: ERROR/MyActivity(5987): connected to service:[email protected]: [email protected] 
06-17 17:29:45.925: DEBUG/dalvikvm(5987): GC_FOR_ALLOC freed 6130K, 18% free 32743K/39815K, paused 24ms 
06-17 17:29:46.005: DEBUG/dalvikvm(5987): GC_FOR_ALLOC freed 883K, 16% free 33737K/39815K, paused 23ms 
06-17 17:29:46.035: DEBUG/dalvikvm(5987): GC_FOR_ALLOC freed 1K, 15% free 33970K/39815K, paused 23ms 

おかげで(のEventServiceサービスである、と私は([OnBind]の中にログインしています)とonUnBind()) 。

答えて

4

ServiceConnection.onServiceConnectedとContext.unbindServiceの間で既知のAndroid-4.0以前の競合状態に遭遇したようです。

Androidの4.0より前のバージョンでは、バインドされたサービスのサービス接続のServiceConnection.onServiceConnectedメソッドの呼び出しを受け取る前にContext.unbindServiceを呼び出すと、フレームワークはコンテキストによってJNI参照をリークします。 android.app.LoadedApk $ ServiceDispatcher $ DeathMonitorオブジェクトの方法です。

あなたがこの問題をヒットしている可能性が非常に高いです - あなたはあなたのログを見れば、あなたはあなたのonUnbindメッセージがonConnectedメッセージの前に印刷されていることがわかります。このバグは修正されました

06-17 17:29:45.875: WARN/EventService(6009): onUnBind() [email protected] 
06-17 17:29:45.875: ERROR/MyActivity(5987): connected to service:[email protected]: [email protected] 

Android 4.0用ここでバグを修正しているコミットします:Androidの以前のバージョンについては

https://github.com/android/platform_frameworks_base/commit/5a6ef737edbf57577443ac056613afe6cb121519

、仕事は、あなたの周りにはServiceConnection.onServiceConnectedへの呼び出しを受けた後までunbindServiceを呼び出す遅延させることです。サービスの接続のonServiceConnectedコールバックメソッド内からContext.unbindServiceを呼び出すことは可能です。

+0

この回答に少し追加しますか? http://developer.android.com/guide/components/bound-services.htmlでは、サンプルコードはonServiceConnected内でtrueに設定された変数mBoundを使用します。したがって、mBoundがtrueの場合にのみunbindを呼び出します。しかし、私は、サンプルコードのアプローチに従えば、onServiceConnectedは、アクティビティが停止または破棄された後でも、最終的に呼び出される可能性が非常に低いと考えていました。おそらくonServiceConnected内には、onStop(またはonDestroy)が呼び出されたかどうかをチェックし、そこからunbindを呼び出すブール値があるかもしれません。 –