Подтвердить что ты не робот

Android StrictMode InstanceCountViolation

Я запускаю свое приложение с StrictMode, активированным в разработке, как описано здесь StrictMode для более низких версий платформы и заметил сообщение об ошибке, которое я не знаю, о чем думать и не могу найти ссылку.

Я получаю android.os.StrictMode$InstanceCountViolation со значениями для instances и limit, например.

экземпляры = 3; предел = 2

Теперь мне интересно:

  • A) как вычисляется предел
  • B) как может произойти такое нарушение, а затем я бы посмотрел на уклончивые действия.

Любые идеи?

4b9b3361

Ответ 1

Все это в коде

Ключ StrictMode.sExpectedActivityInstanceCount и incrementExpectedActivityCount и 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+Click или Shift+Click
  • щелкните правой кнопкой мыши и слейте самый короткий путь к GC Roots > со всеми ссылками

Обход

Если мы увеличиваем количество изначально, у нас будет больше пространства для ног, прежде чем он сообщит об утечке для определенных классов:

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

Дальнейшее чтение

Ответ 2

Кажется, может быть ошибка в проверке StrictMode на некоторых устройствах.

Если действие запущено и вышло и перезапустилось очень быстро, вы можете получить StrictMode.InstanceCountViolation.

Однако это просто потому, что сборщик мусора еще не завершил первый экземпляр Activity, а это значит, что в памяти временно есть 2 (или более) экземпляра.

Calling System.gc() до началаActivity() или startActivityForResult() остановит StrictMode.InstanceCountViolation.

Кажется, это указывает на ошибку (или, возможно, функцию?) в проверке StrictMode.

Ответ 3

Ниже приведено обсуждение групп google об обработке StrictMode InstanceCountViolation. Похоже, что у каждой другой версии Android есть другая политика, поэтому они просто отключили ее. Также в документах Android говорится о Строком режиме

Но не чувствуйте себя обязанным исправить все, что обнаружил StrictMode. В частности, во время обычного жизненного цикла активности часто требуется много случаев доступа к диску. Используйте StrictMode, чтобы найти то, что вы делали случайно. Сетевые запросы в потоке пользовательского интерфейса почти всегда являются проблемой.

Я думаю, что это то, что @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());
 }
}

Ответ 4

Я понимаю, что это нарушение используется для обнаружения утечек памяти. Итак, в этот момент у вас должно быть только 2 экземпляра класса, но VM нашла 3.

Я также видел это нарушение в моем коде, но на мои дополнительные экземпляры все ссылались на слабые указатели. Поэтому я решил отключить это правило.

Ответ 5

Удалите строку, расположенную ниже, из create.

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

Ответ 6

см. приведенный ниже пример, он зависит от версии 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());
    }
}