web-dev-qa-db-fra.com

Android StrictMode InstanceCountViolation

J'exécute mon application avec StrictMode activé en développement comme indiqué ici StrictMode pour les versions de plate-forme inférieures et j'ai remarqué un message d'erreur indiquant que je ne sais pas quoi penser et que je ne peux trouver aucune référence.

J'ai un Android.os.StrictMode$InstanceCountViolation avec des valeurs pour instances et limit par exemple.

instances = 3; limite = 2

Maintenant je me demande:

  • A) Comment est calculée la limite
  • B) comment une telle violation peut-elle réellement se produire et ensuite j'examinerais les actions d'évitement.

Des idées?

48
Manfred Moser

Tout est dans le code

La clé est StrictMode.sExpectedActivityInstanceCount et incrementExpectedActivityCount et decrementExpectedActivityCount :

Ainsi, le limit est moindre à chaque fois qu'une activité est détruite, mais si une instance est divulguée, le nombre d'instances réel sera supérieur à la limite, pour détecter si elle est divulguée, ils font de la magie GC (dans decrementExpectedActivityCount):

    System.gc();
    System.runFinalization(); // added in https://github.com/Android/platform_frameworks_base/commit/6f3a38f3afd79ed6dddcef5c83cb442d6749e2ff
    System.gc();

si après cela, le GC n'a pas supprimé l'activité de la mémoire de l'application, cela est considéré comme une fuite.

Conclusion

Sur la base de ce qui précède, le seul moyen d'empêcher est de s'assurer qu'il n'y a aucune référence à l'activité incriminée après onDestroy. Le problème est que certains peuvent être des WeakReferences qui sont toujours accessibles via certains objets natifs, qui semblent avoir un cycle de vie différent. Voici comment je suis arrivé à cette conclusion:

  • après s'être retiré de MyActivity et avoir vu le message du journal
  • faire un vidage de tas (.hprof)
  • ouvrez-le dans Eclipse Memory Analyzer
  • exécutez OQL: select * from instanceof full.package.name.of.MyActivity
  • tout sélectionner avec Ctrl+Click ou Shift+Click
  • clic droit et Fusionner le chemin le plus court vers les racines GC> avec toutes les références

Workaround

Si nous augmentons le nombre initialement nous aurons plus d'espace pour les jambes avant de signaler la fuite pour des classes spécifiques:

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

Lectures complémentaires

27
TWiStErRob

Il semble qu'il puisse y avoir un bogue dans la vérification de StrictMode sur certains appareils.

Si une activité est démarrée, puis fermée et redémarrée très rapidement, vous pouvez obtenir un StrictMode.InstanceCountViolation.

Cependant, c'est simplement parce que le garbage collector n'a pas encore finalisé la première instance de l'activité, ce qui signifie qu'il y a temporairement 2 (ou plus) instances en mémoire.

L'appel de System.gc () avant startActivity () ou startActivityForResult () arrêtera StrictMode.InstanceCountViolation.

Cela semble indiquer un bogue (ou peut-être une fonctionnalité?) Dans la vérification StrictMode.

9
Neromancer

Voici une discussion sur les groupes Google sur la gestion de StrictMode InstanceCountViolation . Il semble que chaque version différente de Android ait une politique différente, ils semblent donc la désactiver. Les documents Android parlent également de Mode strict

Mais ne vous sentez pas obligé de réparer tout ce que StrictMode trouve. En particulier, de nombreux cas d'accès au disque sont souvent nécessaires pendant le cycle de vie normal des activités. Utilisez StrictMode pour trouver des choses que vous avez faites par accident. Cependant, les requêtes réseau sur le thread d'interface utilisateur sont presque toujours un problème.

Je pense que c'est ce que @sri essaie de montrer avec son code.

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());
 }
}
7
jpotts18

Ma compréhension est que cette violation est utilisée pour détecter les fuites de mémoire. Donc, à ce stade, vous ne devriez avoir que 2 instances de la classe chargées, mais le VM en a trouvé 3.

J'ai également vu cette violation dans mon code, mais mes instances supplémentaires ont toutes été référencées par des pointeurs faibles. J'ai donc choisi de désactiver cette règle.

2
Thierry-Dimitri Roy