sat*_*ine 5 android ipc android-binder
我认为我追踪了内存泄漏,并想确认我认为Android的Binder如何实现的可能性.在这种情况下,我有一个服务和一个活动,每个都在他们自己的过程中.我创建了一个AIDL,它允许我通过ipc方法将Call从对象传递给Service,然后在服务完成所请求的任务时调用回调.
很长一段时间我都在想:如果我将一个新的Callback对象传递给Service,并且我没有在我的Activity中保留一个指向Callback对象的指针,为什么垃圾收集器不会继续并在我的Activity中收集回调处理?由于这似乎没有发生,JVM如何知道何时在我的Activity中垃圾收集回调.
我认为答案是Binder系统在Activity进程中保留一个指向我的Callback的指针,直到Service进程中相应的Callback对象调用了finalize()方法,然后向Activity发送一条消息以释放指针.它是否正确?如果不是,它是如何工作的?
我相信它是并且它导致有趣的情况,如果活动中的回调指向非常占用内存的东西,则在收集服务中的回调之前不会收集它.如果服务内存不足,它可能不会长时间收集回调,并且回调可能只是在活动中积累,直到活动中出现OutOfMemoryError.
Yury非常正确.
我的服务启动一个保存回调的线程,当线程完成其工作时,它调用回调并且线程结束.当调用回调时,它可能会在我的Activity中做一些工作,然后返回,此时我的Activity进程中没有指向回调的指针.
但是,活动中的回调对象将继续由Android的活页夹系统指向,直到服务中的相应回调对象被垃圾收集.
如果Activity进程中的回调对象支配一些消耗大量内存的其他对象,那么我在我的Activity进程中浪费内存是没有充分理由的,甚至可能得到一个OutOfMemoryError.解决方案是在我的回调类中创建一个简单的方法,调用destory()null来取消所有回调的字段,并在完成回调时调用该方法.
如果回调类是非静态内部类,您可能需要考虑将其更改为静态内部类并在构造函数中传入父类,这样您也可以在destory()方法中将其取消.
这提出了一个有趣的想法,如果非静态内部回调类的父类是一个Activity,并且在通过绑定器发送回调之后但在回调之前发生配置更改(例如屏幕旋转),那么回调将在执行时指向旧的Activity对象!
更新:我在Binder.java中发现了这个代码,当然它被禁用但如果他们在Javadocs中提到这种东西会很好.
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Binder> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Binder class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
Run Code Online (Sandbox Code Playgroud)