Релевантно только тем, что он мотивирует устранение любых ложных срабатываний из строгой моды, поскольку постоянное присутствие любого человека делает смертную казнь нецелесообразной
В течение последних нескольких дней я преследовал и исправлял утечки памяти в приложении. Поняв, что я полагал, что исправил их все, я применил отказоустойчивый механизм, подобный описанному в Android StrictMode и кучи дампов (включить отслеживание экземпляров со смертной казнью, перехватить сообщение об ошибке завершения работы, кучу дампа, отправить сигнал бедствия при следующем запуске приложения). Все просто в отладочных сборках, конечно.
К точке
Полагая, что я исправил все утечки активности, определенные действия по-прежнему приводят к появлению сообщений о нарушении правил экземпляра строгого режима при вращении экрана. Любопытно, что это только некоторые, а не все приложения, которые это делают.
Я рассмотрел кучи кучи, полученные при таких нарушениях, и рассмотрел код рассматриваемых действий в поисках утечки, но никуда не денусь.
Итак, в этот момент я попытался сделать наименьший возможный тестовый пример. Я создаю полностью пустую активность (без макета), выглядя так:
package com.example.app;
import android.app.Activity;
import android.os.Bundle;
import android.os.StrictMode;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
StrictMode.setVmPolicy(
new StrictMode.VmPolicy.Builder()
.detectAll()
.penaltyLog()
.build());
StrictMode.setThreadPolicy(
new StrictMode.ThreadPolicy.Builder()
.detectAll()
.penaltyDeath()
.penaltyLog()
.build());
super.onCreate(savedInstanceState);
}
}
И для полноты, манифест:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.app" >
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.example.app.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Я открываю действие (портрет, удерживаемый устройством). Я поворачиваюсь к пейзажу и возвращаюсь к портрету, и в этот момент я вижу из StrictMode это в LogCat:
01-15 17: 24: 23.248: E/StrictMode (13867): класс com.example.app.MainActivity; экземпляры = 2; предел = 1 01-15 17: 24: 23.248: E/StrictMode (13867): android.os.StrictMode $InstanceCountViolation: класс com.example.app.MainActivity; экземпляры = 2; предел = 1 01-15 17: 24: 23.248: E/StrictMode (13867): at android.os.StrictMode.setClassInstanceLimit(StrictMode.java:1)
Куча кучи
В этот момент я вручную получаю кучу кучи, используя DDMS. Вот два примера в MAT:
И вот тот, который просочился, с первой частью пути от него до корня GC:
Обратите внимание, что независимо от того, сколько раз я вращаюсь между портретом и ландшафтом, количество фактических экземпляров никогда не превышает двух, а количество ожидаемых экземпляров никогда не превышает один.
Может ли кто-нибудь понять утечку? Это даже настоящая утечка? Если это так, вероятно, это ошибка Android. Если это не так, единственное, что я вижу, это может быть ошибка в StrictMode.
Хорошие ответы могут включать
- Если это настоящая утечка, объяснение того, как это происходит, и что, если можно предпринять какие-либо действия для ее исправления или подавить StrictMode от начала смертной казни за такие случаи (напомните, что ложные срабатывания/нейтралитеты делают смертную казнь непрактично).
- Если это не настоящая утечка, объяснение того, почему StrictMode думает иначе, и что, если можно предпринять какие-либо действия для его устранения или подавить StrictMode от начала смертной казни для таких случаев (напомните, что ложные срабатывания/нейтрали делают смертная казнь непрактична).
- В любом случае, гипотезы о том, почему это не происходит со всеми действиями (большинство действий в приложении, над которым я работаю, не порождают таких нарушений при ротации).
Я дошел до источника StrictMode и не вижу ничего явно неправильного - как и ожидалось, он заставляет GC, прежде чем рассматривать дополнительный экземпляр как нарушение.
Хорошие точки входа для чтения источника StrictMode:
- http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.4_r1/android/os/StrictMode.java#StrictMode.trackActivity%28java.lang.Object%29
- http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.4_r1/android/os/StrictMode.java#StrictMode.InstanceTracker.finalize%28%29
- http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.4_r1/android/os/StrictMode.java#StrictMode.incrementExpectedActivityCount%28java.lang.Class%29
- http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.4_r1/android/os/StrictMode.java#StrictMode.decrementExpectedActivityCount(java.lang.Class)
Полное раскрытие информации
Я только делал эти тесты на одном устройстве, Galaxy S4 запускал CyanogenMod 11 моментальный снимок M2 (http://download.cyanogenmod.org/get/jenkins/53833/cm-11-20140104-SNAPSHOT-M2-jfltexx.zip), но я не может представить, что CyanogenMod будет отклоняться от KitKat с точки зрения управления деятельностью.
Дополнительные источники StrictMode:
- Экземпляр экземпляра instanceTracker - это только поле конечного экземпляра: http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.4_r1/android/app/Activity.java#Activity.0mInstanceTracker
- Ожидаемые значения экземпляров экземпляров увеличиваются: http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.4_r1/android/app/ActivityThread.java#2095
- Ожидается, что ожидаемые значения экземпляра активности уменьшатся: http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.4_r1/android/app/ActivityThread.java#3485