Android StrictMode InstanceCountViolation
android-strictmode (6)
Está todo en el código
La clave es StrictMode.sExpectedActivityInstanceCount
y incrementExpectedActivityCount
y decrementExpectedActivityCount
:
- Se llama incremento en
ActivityThread.performLaunchActivity
Justo después de crear la instancia de laActivity
. - Decremento se llama en
ActivityThread.performDestroyActivity
Después de que la actividad ha sido eliminada de la aplicación.
Por lo tanto, el limit
es menor cada vez que se destruye una actividad; sin embargo, si se filtra una instancia, el número de instancias reales será mayor que el límite, para detectar si se filtra hacen algo de magia GC (en decrementExpectedActivityCount
):
System.gc();
System.runFinalization(); // added in https://github.com/android/platform_frameworks_base/commit/6f3a38f3afd79ed6dddcef5c83cb442d6749e2ff
System.gc();
si después de esto, el GC no eliminó la actividad de la memoria de la aplicación, se considera una fuga.
Conclusión
Basado en lo anterior, la única forma de prevenir es asegurarse de que no haya referencias a la actividad ofensiva después de onDestroy
. El problema es que algunos pueden tener algunas WeakReference
que todavía son accesibles a través de algunos objetos nativos, que parecen tener un ciclo de vida diferente. Así es como llegué a esta conclusión:
- después de retirarse de
MyActivity
y ver el mensaje de registro - hacer un volcado de pila (.hprof)
- Ábrelo en Eclipse Memory Analyzer.
- ejecute OQL:
select * from instanceof full.package.name.of.MyActivity
- seleccionar todo con Ctrl + Clic o Mayús + Clic
- haga clic con el botón derecho y fusione la ruta más corta a las raíces GC> con todas las referencias
Solución
Si aumentamos el conteo inicialmente , tendremos más espacio para las piernas antes de que informe la pérdida para clases específicas:
// 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);
Otras lecturas
Estoy ejecutando mi aplicación con StrictMode activado en desarrollo como se documenta aquí StrictMode para versiones de plataforma más bajas y noté un mensaje de error que no sé qué pensar ni puedo encontrar ninguna referencia.
Obtengo un android.os.StrictMode$InstanceCountViolation
con valores para instances
y limit
por ejemplo
instancias = 3; límite = 2
Ahora me estoy preguntando:
- A) ¿Cómo se calcula el límite?
- B) ¿Cómo puede realmente ocurrir una violación de este tipo y luego vería acciones evasivas?
¿Algunas ideas?
Aquí hay una discusión sobre los grupos de google sobre el manejo de StrictMode InstanceCountViolation . Parece que cada versión diferente de Android tiene una política diferente, así que parece que simplemente la deshabilitan. También los documentos de Android dicen sobre el modo estricto
Pero no se sienta obligado a arreglar todo lo que StrictMode encuentra. En particular, muchos casos de acceso al disco a menudo son necesarios durante el ciclo de vida normal de la actividad. Usa StrictMode para encontrar cosas que hiciste por accidente. Sin embargo, las solicitudes de red en el subproceso de la interfaz de usuario son casi siempre un problema.
Creo que eso es lo que @sri está tratando de mostrar con su código.
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());
}
}
Eliminar la línea de abajo de crear
//StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectAll().penaltyLog().penaltyDeath().detectLeakedSqlLiteObjects().build());
Mi entendimiento es que esta violación se usa para detectar fugas de memoria. Entonces, en ese punto, solo debería tener 2 instancias de la clase cargadas, pero la máquina virtual encontró 3.
También he visto esta violación en mi código, pero todas mis instancias adicionales fueron referenciadas por punteros débiles. Así que elijo deshabilitar esta regla.
Parece que puede haber un error en la comprobación de StrictMode en algunos dispositivos.
Si se inicia una Actividad, se cierra y se reinicia muy rápidamente, puede obtener un StrictMode.InstanceCountViolation.
Sin embargo, esto es simplemente porque el recolector de basura aún no ha finalizado la primera instancia de la Actividad, lo que significa que hay temporalmente 2 (o más) instancias en la memoria.
Llamar a System.gc () antes de startActivity () o startActivityForResult () detendrá StrictMode.InstanceCountViolation.
Esto parece indicar un error (¿o quizás una característica?) En la comprobación de StrictMode.
Vea el siguiente ejemplo que varía según la versión de 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());
}
}