Android StrictMode InstanceCountViolation

时间:2011-05-10 20:34:32

标签: android android-strictmode

我正在运行我的应用程序,在开发中激活StrictMode,如此处所述StrictMode for lower platform versions 并注意到一条错误信息,我不知道该怎么想,也找不到任何参考。

我得到android.os.StrictMode$InstanceCountViolation instanceslimit的值,例如

  

实例= 3;极限= 2

现在我想知道:

  • A)如何计算限额
  • B)这样的违规行为究竟是如何发生的,然后我会调查回避行动。

有什么想法吗?

6 个答案:

答案 0 :(得分:26)

全部在代码

关键是StrictMode.sExpectedActivityInstanceCount and incrementExpectedActivityCount and decrementExpectedActivityCount

因此,每次活动被销毁时limit都会减少,但是如果某个实例被泄露,实际实例数将大于限制,以检测它是否泄露它们是否会产生一些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 +单击
  • 全选
  • 右键单击并合并到GC根的最短路径>所有参考文献

解决方法

如果我们increase the count initially我们在报告特定类别的泄漏之前会有更多的腿部空间:

// 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);

进一步阅读

答案 1 :(得分:9)

似乎某些设备上的StrictMode检查中可能存在错误。

如果Activity已启动,并且很快退出并重新启动,则可以获得StrictMode.InstanceCountViolation。

然而,这只是因为垃圾收集器尚未完成活动的第一个实例,这意味着内存中暂时有2个(或更多个)实例。

在startActivity()或startActivityForResult()之前调用System.gc()将停止StrictMode.InstanceCountViolation。

这似乎表明StrictMode检查中存在错误(或者可能是某个功能?)。

答案 2 :(得分:7)

以下是有关处理StrictMode InstanceCountViolation的Google群组的讨论。看起来每个不同的Android版本都有不同的策略,因此它们似乎只是禁用它。此外,Android文档还提到Strict Mode

  

但是不要觉得有必要修复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());
 }
}

答案 3 :(得分:2)

我的理解是这种违规用于检测内存泄漏。因此,此时您应该只加载2个类的实例,但VM找到3个。

我在代码中也看到了这种违规行为,但是我的额外实例都被弱指针引用了。所以我选择禁用此规则。

答案 4 :(得分:-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());
    }
}

答案 5 :(得分:-3)

从创建时删除下面的一行。

//StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectAll().penaltyLog().penaltyDeath().detectLeakedSqlLiteObjects().build());