内存泄漏管理活动onResume / onPause中的服务连接

时间:2011-06-18 01:06:25

标签: android

我已经在我的应用中发现了严重的内存泄漏问题,在快速创建/销毁活动时管理与服务的连接(或者可能很快恢复/暂停;至少这是我根据测试的想法)。< / p>

我想帮助了解导致此问题的原因以及如何正确解决问题。 当我从另一个应用程序切换到我的应用程序时,会发生这种情况,并且屏幕方向不同(并且我保持连接对象的活动不在前台)。

我有一堆活动似乎无法被垃圾收集,因为它们似乎仍被引用:  GC根目录下的'LoadedApk $ ServiceDispatcher $ DeathMonitor'对象。

我在onResume()中调用bind,在onPause()中调用unBind。 在做了一些实验之后,我相信我以某种方式绑定/取消绑定问题的根本原因。例如,如果我停止调用unbind,内存泄漏停止但我得到一些ConnectionLeaked异常(我理解他们的原因)。 也许在连接对象收到通知之前调用unbind会以某种方式导致此问题(但我没有看到logcat中的错误,并且服务正确接收绑定/解除绑定调用)。

当我使用Eclipse Memory Analyzer时(我在我的应用程序和另一个应用程序之间来回切换几次之后),我看到一堆活动实例,其中包含以下GC根目录路径:

MyActivity

&lt; - mContext android.app.LoadedApk $ ServiceDispatcher @ 0x41059d6

&lt; ----这个$ 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:MyActivity@408753a0
06-17 17:29:45.015: WARN/EventService(6009): onBind() MyActivity@408753a0
06-17 17:29:45.025: WARN/MyActivity(5987): MyActivity onPause()
06-17 17:29:45.025: WARN/MyActivity(5987): unbinding from service:MyActivity@408753a0
06-17 17:29:45.025: WARN/EventService(6009): onUnBind() MyActivity@408753a0
06-17 17:29:45.025: ERROR/MyActivity(5987): connected to service:MyActivity@408753a0connection: com.yogiplay.apps.MyActivity$1@40878328
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:MyActivity@409e4c00
06-17 17:29:45.875: WARN/EventService(6009): onBind() MyActivity@409e4c00
06-17 17:29:45.875: WARN/MyActivity(5987): MyActivity onPause()
06-17 17:29:45.875: WARN/MyActivity(5987): unbinding from service:MyActivity@409e4c00
06-17 17:29:45.875: WARN/EventService(6009): onUnBind() MyActivity@409e4c00
06-17 17:29:45.875: ERROR/MyActivity(5987): connected to service:MyActivity@409e4c00connection: com.yogiplay.apps.MyActivity$1@409e4d20
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

感谢您的帮助。

1 个答案:

答案 0 :(得分:4)

看起来你在ServiceConnection.onServiceConnected和Context.unbindService之间遇到了已知的Android-4.0之前的竞争状态。

在Android-4.0之前的Android版本中,如果在收到对绑定服务的服务连接的ServiceConnection.onServiceConnected方法的调用之前调用Context.unbindService,则框架将通过方式泄漏对您的上下文的JNI引用android.app.LoadedApk $ ServiceDispatcher $ DeathMonitor对象。

您很可能遇到此问题 - 如果您查看日志,您会看到在onConnected消息之前正在打印您的onUnbind消息:

06-17 17:29:45.875: WARN/EventService(6009): onUnBind() MyActivity@409e4c00
06-17 17:29:45.875: ERROR/MyActivity(5987): connected to service:MyActivity@409e4c00connection: com.yogiplay.apps.MyActivity$1@409e4d20

此错误已针对Android 4.0修复。这是修复错误的提交:

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

对于早期版本的Android,解决方法是在收到对ServiceConnection.onServiceConnected的调用之后延迟调用unbindService。对于它的价值,可以在服务连接的onServiceConnected回调方法中调用Context.unbindService。