web-dev-qa-db-ja.com

Android StrictMode InstanceCountViolation

ここに記載されているように、開発中にStrictModeをアクティブにしてアプリを実行しています 下位プラットフォームバージョンの場合はStrictMode

Android.os.StrictMode$InstanceCountViolationinstancesおよびlimitの値を指定します。

インスタンス= 3; limit = 2

今私は疑問に思っています:

  • A)制限の計算方法
  • B)そのような違反が実際にどのように発生し、それから回避行動を検討することができるか。

何か案は?

48
Manfred Moser

すべてコード内にあります

キーは 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の後に問題のあるアクティビティへの参照がないことを確認することです。問題は、いくつかのWeakReferencesがいくつかのネイティブオブジェクトを介してまだアクセス可能であり、ライフサイクルが異なるように見えることです。この結論に至った経緯は次のとおりです。

  • MyActivityからバックアウトし、ログメッセージを表示した後
  • ヒープダンプを作成します(.hprof)
  • Eclipse Memory Analyzerで開きます
  • oQLを実行:select * from instanceof full.package.name.of.MyActivity
  • ですべてを選択 Ctrl+Click または Shift+Click
  • 右クリックしてGCルートへの最短パスをマージ>すべての参照で

Workaround

最初にカウントを増やす の場合、特定のクラスのリークを報告する前により多くのレッグルームがあります。

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

参考文献

27
TWiStErRob

一部のデバイスのStrictModeチェックにバグがあるようです。

アクティビティが開始され、すぐに終了して再起動されると、StrictMode.InstanceCountViolationを取得できます。

ただし、これは単にガベージコレクターがアクティビティの最初のインスタンスをまだ完了していないためです。つまり、一時的に2つ(またはそれ以上)のインスタンスがメモリにあります。

StartActivity()またはstartActivityForResult()の前にSystem.gc()を呼び出すと、StrictMode.InstanceCountViolationが停止します。

これは、StrictModeチェックのバグ(または機能かどうか)を示しているようです。

9
Neromancer

StrictMode InstanceCountViolation の処理に関するGoogleグループの説明を次に示します。すべての異なるAndroidバージョンには異なるポリシーがあるため、単に無効にするようです。また、Android docs say about 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());
 }
}
7
jpotts18

私の理解では、この違反はメモリリークの検出に使用されます。その時点で、クラスのインスタンスを2つだけロードする必要がありますが、VM found 3。

この違反はコードでも見ましたが、余分なインスタンスはすべて弱いポインターによって参照されていました。そこで、このルールを無効にすることにしました。

2