我已经确定了我的应用程序中严重的内存泄漏问题,当一个活动快速创建/销毁(或可能很快恢复/暂停;至少这是管理连接到服务我正在考虑基于测试)。内存泄漏管理服务连接在活动onResume/onPause
我想了解一些有助于理解是什么导致了这种情况,以及如何正确解决这个问题。 当我从另一个应用程序切换到我的应用程序时,屏幕方向不同(并且我的活动持有连接对象不在前台)。
我有一堆似乎无法收集垃圾的活动,因为它们似乎仍然被GC引用: 'LoadedApk $ ServiceDispatcher $ DeathMonitor'对象位于GC根目录。
我在onResume()中调用bind并在onPause()中取消绑定。 做了一些实验后,我相信我以某种方式绑定/解除绑定问题的根本原因。例如,如果我停止调用解绑,内存泄漏停止,但我得到一些ConnectionLeaked异常(我明白他们的原因)。 也许在连接对象收到通知之前调用解除绑定会导致此问题(但我在logcat中看不到错误,并且该服务正确接收绑定/解除绑定调用)。
我看到一堆活动实例有以下路径GC根当我使用Eclipse的内存分析器(后我来回切换我的应用程序和其他应用程序之间的几次):
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日志是这样的:(EventService是服务,我在onBind记录()和onUnBind())
<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
感谢您的帮助。
想补充一点这个答案。在http://developer.android.com/guide/components/bound-services.html中,示例代码使用在onServiceConnected中设置为true的变量mBound;因此,只有在mBound为真时才调用解除绑定。但是,我认为如果我们遵循示例代码的方法,即使在活动停止或销毁之后,最终仍会调用onServiceConnected(非常小)的机会;所以也许在onServiceConnected中,有一个布尔值来检查onStop(或onDestroy)是否被调用,并从那里调用解除绑定。 –