Analyser les fuites de mémoire dans une
application Android
Smart&Soft
Smart&Soft conçoit, réalise et pilote des applications mobiles pour smartphones, tablettes, montres et TV connectées.
Nos références clients dans tous les secteurs d’activité
Centré utilisateur Des applications performantes
et de qualité
Orienté performanceAssurer la pérennité de vos
applications avec des outils dédiés
2
Qui suis-je ?
Ludovic Roland
Responsable du pôle Android
Ingénieur en développement logiciel Android, Windows Phone / Store et Windows 10.
@ludovicroland@smartnsoft
3
Introduction
➜ Des fuites de mémoire en Java ?
➜ Des conséquences bien présentes...
4
5
1. Les fausses solutions
2. Les requêtes OQL
3. L’histogramme
4. La bibliothèque LeakCanary
Plan Plan
1.Les fausses solutions
6
Les fausses solutions
➜ Le manifest
➜ try / catch tous les blocs de code qui peuvent être à l’origine d’une exception de type OutOfMemoryError
<application ... android:largeHeap="true" ...> <!-- --></application>
7
Trouver une vraie solution avec MAT
8
Le logiciel indispensable...
➜ Eclipse Memory Analyzer (MAT)
➜ http://www.eclipse.org/mat/
9
Le processus de création du fichier hprof
1. Création d’un fichier hprof via Android Studio
a. Compilation de l’application
b. On navigue dans l’application (l’empreinte mémoire est visible dans l’onglet Android Monitor)
c. On ferme l’application (bouton retour du téléphone)
Ne pas tuer l’application !
d. On force le passage du Garbage Collector ( )10
Le processus de création du fichier hprof (suite)
1. Création d’un fichier hprof via Android Studio (suite)
e. Génération du fichier hprof ( )
11
Le processus de création du fichier hprof (suite)
1. Création d’un fichier hprof via Android Studio (suite)
f. Transformation du fichier hprof dans un format “standard”
g. Ouvrir le nouveau fichier hprof dans MAT
12
Présentation de la fuite de mémoire
public final class MainFragment extends Fragment{
private final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { //TODO } };
@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { final View view = inflater.inflate(R.layout.fragment_main, container, false);
final IntentFilter intentFilter = new IntentFilter("TEST"); LocalBroadcastManager.getInstance(getContext()).registerReceiver(broadcastReceiver, intentFilter);
return view; }
}
13
2. Les requêtes OQL
14
OQL (Object Query Language) est une extension du langage SQL pour base de données orientées objet
[...]
Wikipedia, https://fr.wikipedia.org/wiki/Object_Query_Language
15
A la recherche de la fuite de mémoire
1. Saisir la requête OQL et observer le résultat
2. Compter les fuites mémoire !
16
Comprendre la fuite de mémoire
1. Afficher le détail de la fuite mémoire
2. Observer, comprendre et interpréter le résultat :
17
Il faut savoir ce que l’on recherche !
18
Un langage complet
➜ SELECT * FROM com.smartnsoft.droid4me.app.Droid4mizer
➜ SELECT * FROM INSTANCEOF android.app.Activity a WHERE a.mDestroyed = true
➜ SELECT s.getValueAt(2) FROM int[] s WHERE (s.@length > 2)
19
3.L’histogramme
20
A la recherche de la fuite de mémoire
1. Cliquer sur l’icône Histogram ( )
2. Filtrer avec le nom de package de votre application :
21
Comprendre la fuite de mémoire
1. Afficher le détail de la fuite mémoire
2. Observer, comprendre et interpréter le résultat :
22
Vérifier la disparition de la fuite de mémoire
1. Filtrer avec le nom de package de votre application :
23
4. La bibliothèque
LeakCanary
24
Présentation de la bibliothèque
➜ Bibliothèque permettant de détecter des fuites de mémoire lorsqu’un utilisateur navigue au sein d’une application
➜ Open-source
➜ Créée par Square
➜ https://github.com/square/leakcanary
25
Intégration de la bibliothèque
➜ Une dépendance dans le build.gradle :
➜ Dans l’application :
dependencies{ testCompile 'junit:junit:4.12' compile 'com.android.support:appcompat-v7:23.2.1' compile 'com.android.support:design:23.2.1'
debugCompile 'com.squareup.leakcanary:leakcanary-android:1.4-beta2' releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.4-beta2' testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.4-beta2'}
public final class CustomApplication extends Application{
@Override public void onCreate() { super.onCreate() ; LeakCanary. install(this); }} 26
LeakCanary se manifeste de lui même...
➜ Affichage d’une notification en cas de comportement suspect
➜ Affichage d’une trace
04-13 14:22:00.864 16128-17526/fr.rolandl.myapplication D/LeakCanary: In fr.rolandl.myapplication:1.0:1.04-13 14:22:00.864 16128-17526/fr.rolandl.myapplication D/LeakCanary: * fr.rolandl.myapplication.MainActivity has leaked:04-13 14:22:00.864 16128-17526/fr.rolandl.myapplication D/LeakCanary: * GC ROOT static android.support.v4.content.LocalBroadcastManager.mInstance04-13 14:22:00.864 16128-17526/fr.rolandl.myapplication D/LeakCanary: * references android.support.v4.content.LocalBroadcastManager.mReceivers04-13 14:22:00.864 16128-17526/fr.rolandl.myapplication D/LeakCanary: * references java.util.HashMap.table04-13 14:22:00.864 16128-17526/fr.rolandl.myapplication D/LeakCanary: * references array java.util.HashMap$HashMapEntry[].[5]04-13 14:22:00.864 16128-17526/fr.rolandl.myapplication D/LeakCanary: * references java.util.HashMap$HashMapEntry.key04-13 14:22:00.864 16128-17526/fr.rolandl.myapplication D/LeakCanary: * references fr.rolandl.myapplication.MainActivity$1.this$0 (anonymous subclass of android.content.BroadcastReceiver)04-13 14:22:00.864 16128-17526/fr.rolandl.myapplication D/LeakCanary: * leaks fr.rolandl.myapplication.MainActivity instance04-13 14:22:00.864 16128-17526/fr.rolandl.myapplication D/LeakCanary: * Retaining: 4,3 Ko.04-13 14:22:00.864 16128-17526/fr.rolandl.myapplication D/LeakCanary: * Reference Key: 605c2fc0-77e1-4027-8999-5014c3cc9215...
27
LeakCanary affiche les détails...
➜ Il convient de cliquer sur la notification pour ouvrir le détail de la potentielle fuite mémoire.
ou
➜ ouvrir l’écran dédié
28
LeakCanary affiche les détails… (suite)
29
Des questions ?
Plus d’informations sur notre blog :
https://medium.com/smart-soft
30
31
Ludovic Roland
Responsable du pôle Android
Ingénieur en développement logiciel Android, Windows Phone / Store et Windows 10.
@ludovicroland@smartnsoft
Smart&Soft
Siège social : 69, rue Saint Lazare – 75 009 - Paris
Bureaux : 45, rue Jean Jaurès – 92 300 - Levallois
01 41 06 15 26
32