Android StrictMode InstanceCountViolation
我正在运行我的应用程序与StrictMode在开发中激活,这里logging的StrictMode为较低的平台版本,并注意到一个错误消息,我不知道该怎么想,也不能find任何参考。
我得到一个android.os.StrictMode$InstanceCountViolation
的值和limit
例如
实例= 3; 极限= 2
现在我想知道:
- A)如何计算极限
- B)怎样才能真正发生这样的违规行为,然后我会考虑回避行动。
有任何想法吗?
这些都在代码中
关键是StrictMode.sExpectedActivityInstanceCount
和incrementExpectedActivityCount
和decrementExpectedActivityCount
:
- 在
ActivityThread.performLaunchActivity
调用Increment
只是在创buildActivity
实例之后。 - 在
ActivityThread.performDestroyActivity
调用减量
活动已从应用程序中删除后。
所以每当一个活动被破坏的时候,这个limit
就会减less,但是如果一个实例被泄露了,真实的实例数将会大于这个限制,为了检测它是否被泄漏了,他们会执行一些GC魔术(在decrementExpectedActivityCount
):
System.gc(); System.runFinalization(); // added in https://github.com/android/platform_frameworks_base/commit/6f3a38f3afd79ed6dddcef5c83cb442d6749e2ff System.gc();
如果在此之后GC没有从应用程序的内存中删除该活动,则认为是泄漏。
结论
基于上面的唯一方法是确保在onDestroy
之后没有对违规活动的引用。 问题是可能有一些WeakReference
可以通过一些本地对象访问,这些对象似乎有不同的生命周期。 下面是我得出这个结论的方法:
- 退出
MyActivity
并看到日志消息后 - 做一个堆转储(.hprof)
- 在Eclipse Memory Analyzer中打开它
- 运行OQL:
select * from instanceof full.package.name.of.MyActivity
- 用Ctrl +单击或Shift +单击select全部
- 右键单击并合并到GC根的最短path>与所有引用
解决方法
如果我们最初增加计数 ,那么在报告特定类别的泄漏之前,我们会有更多的空间:
// Application.onCreate or nearby where you set up StrictMode detectActivityLeaks Method incrementExpectedActivityCount = StrictMode.class.getMethod("incrementExpectedActivityCount", Class.class) incrementExpectedActivityCount.invoke(null, MyActivity.class); incrementExpectedActivityCount.invoke(null, MyActivity2.class);
进一步阅读
-
WeakReference
s - Eclipse内存分析器(MAT)
-
StrictMode
历史
看来有些设备上的StrictMode检查可能存在一个错误。
如果一个Activity被启动,并且很快退出并重新启动,你可以得到一个StrictMode.InstanceCountViolation。
但是,这只是因为垃圾收集器尚未完成Activity的第一个实例,这意味着内存中暂时存在2个(或更多)实例。
在startActivity()或startActivityForResult()之前调用System.gc()将停止StrictMode.InstanceCountViolation。
这似乎表明在StrictMode检查中的一个错误(或者一个function?)。
以下是关于处理StrictMode InstanceCountViolation的谷歌群组的讨论。 它看起来像每个不同的Android版本有不同的政策,所以他们似乎只是禁用它。 Android文档也提到严格模式
但是不要强迫所有StrictMode发现。 特别是,在正常的活动生命周期中,通常需要很多磁盘访问的情况。 使用StrictMode来查找你意外做的事情。 但是,UI线程上的networking请求几乎总是一个问题。
我认为这就是@sri试图用他的代码展示的东西。
public class MyApplication extends Application { @Override public void onCreate (){ super.onCreate(); // when you create a new application you can set the Thread and VM Policy StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() .detectCustomSlowCalls() // API level 11, to use with StrictMode.noteSlowCode .detectDiskReads() .detectDiskWrites() .detectNetwork() .penaltyLog() .penaltyFlashScreen() // API level 11 .build()); //If you use StrictMode you might as well define a VM policy too StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder() .detectLeakedSqlLiteObjects() .detectLeakedClosableObjects() // API level 11 .setClassInstanceLimit(Class.forName(“com.apress.proandroid.SomeClass”), 100) .penaltyLog() .build()); } }
我的理解是,这种违规行为是用来检测内存泄漏。 所以在这一点上,你应该只加载了2个类的实例,但find了3个虚拟机。
我在我的代码中也看到了这个违例,但是我的额外实例都被弱指针引用。 所以我select禁用这个规则。
从创build时删除下面的行。
//StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectAll().penaltyLog().penaltyDeath().detectLeakedSqlLiteObjects().build());
看下面的例子,它根据Android版本而变化
public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() .detectCustomSlowCalls() // API level 11, to use with StrictMode.noteSlowCode .detectDiskReads() .detectDiskWrites() .detectNetwork() .penaltyLog() .penaltyFlashScreen() // API level 11 .build()); // not really performance-related, but if you use StrictMode you might as well define a VM policy too StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder() .detectLeakedSqlLiteObjects() .detectLeakedClosableObjects() // API level 11 .setClassInstanceLimit(Class.forName(“com.apress.proandroid.SomeClass”), 100) // API level 11 .penaltyLog() .build()); } }