我正在使用开发中激活的 StrictMode 运行我的应用程序,如此处记录的StrictMode 用于较低平台版本 ,并注意到一条错误消息,我不知道要考虑什么,也找不到任何参考。
我得到了一个android.os.StrictMode$InstanceCountViolation
值instances
,limit
例如
实例=3;限制=2
现在我想知道:
- A) 限额是如何计算的
- B)这种违规行为如何实际发生,然后我会调查规避行为。
有任何想法吗?
我正在使用开发中激活的 StrictMode 运行我的应用程序,如此处记录的StrictMode 用于较低平台版本 ,并注意到一条错误消息,我不知道要考虑什么,也找不到任何参考。
我得到了一个android.os.StrictMode$InstanceCountViolation
值instances
,limit
例如
实例=3;限制=2
现在我想知道:
有任何想法吗?
ActivityThread.performLaunchActivity
Activity
instance.ActivityThread.performDestroyActivity
So the limit
is less each time an activity is destroyed, however if an instance is leaked the real instance count will be bigger than the limit, to detect if it's leaked they do some GC magic (in decrementExpectedActivityCount
):
System.gc();
System.runFinalization(); // added in https://github.com/android/platform_frameworks_base/commit/6f3a38f3afd79ed6dddcef5c83cb442d6749e2ff
System.gc();
if after this the GC didn't remove the activity from the app's memory it is considered a leak.
Based on the above the only way to prevent is to make sure there are no references to the offending activity after onDestroy
. The problem is that some there may be some WeakReference
s which are still accessible through some native objects, which seem to have a different lifecycle. Here's how I came to this conclusion:
MyActivity
and seeing the log messageselect * from instanceof full.package.name.of.MyActivity
If we increase the count initially we'll have more legroom before it reports the leak for specific classes:
// 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);
It seems there might be a bug in the StrictMode checking on some devices.
If an Activity is started, and exited and restarted very quickly, you can get a StrictMode.InstanceCountViolation.
However this is simply because the garbage collector has not yet finalized the first instance of the Activity, meaning there are temporarily 2 (or more) instances in memory.
Calling System.gc() before startActivity() or startActivityForResult() will stop the StrictMode.InstanceCountViolation.
This seems to indicate a bug (or perhaps a feature?) in the StrictMode checking.
这是关于处理StrictMode InstanceCountViolation的 Google 群组的讨论。看起来每个不同的 Android 版本都有不同的政策,所以他们似乎只是禁用它。Android 文档也提到了严格模式
但不要觉得有必要修复 StrictMode 找到的所有内容。特别是,在正常的活动生命周期中,许多磁盘访问情况通常是必要的。使用 StrictMode 查找您不小心做的事情。不过,UI 线程上的网络请求几乎总是一个问题。
我认为这就是@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 个该类的实例,但 VM 找到了 3 个。
我在我的代码中也看到了这种违规行为,但是我的额外实例都被弱指针引用。所以我选择禁用这个规则。
请参阅下面的示例,它根据 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());
}
}
Remove the line below from on create.
//StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectAll().penaltyLog().penaltyDeath().detectLeakedSqlLiteObjects().build());