Résumé des fuites de mémoire Android et conseils d'optimisation des performances

       Lorsque nous développons des applications Android, l’optimisation des performances est un aspect très important. D'une part, l'optimisation peut améliorer la vitesse de réponse de l'application, réduire le taux de décalage et améliorer la fluidité de l'application, améliorant ainsi l'expérience utilisateur ; d'autre part, l'optimisation peut également réduire l'utilisation des ressources de l'application, améliorer la stabilité et la sécurité de l'application, et réduire le coût de l'application.la probabilité d'être tuée, améliorant ainsi la satisfaction et la rétention des utilisateurs.

      Cependant, pour de nombreux développeurs, l’optimisation des performances Android est souvent une question difficile. Puisqu’il existe de nombreux types d’appareils Android avec des configurations matérielles différentes, les méthodes et stratégies d’optimisation sont également différentes. Dans le même temps, le cycle de développement des applications Android est long et nécessite souvent des itérations et des mises à jour continues. L'optimisation doit donc également être poursuivie et optimisée.

        Apprendre les connaissances et les compétences en matière d’optimisation des performances Android est l’une des compétences essentielles pour tout développeur Android. En maîtrisant les principes et méthodes de base de l'optimisation des performances Android, nous pouvons avoir une compréhension plus approfondie du mécanisme de fonctionnement des appareils Android et comprendre les goulots d'étranglement des performances des applications, afin d'adopter des stratégies et des mesures d'optimisation efficaces pour améliorer les performances et la stabilité des applications et améliorer satisfaction des utilisateurs et taux de rétention.


       Cet article présente les principes de base, les stratégies d'optimisation et les techniques pratiques d'optimisation des performances Android pour aider les développeurs à mieux comprendre le principe de fonctionnement des appareils Android et à maîtriser les méthodes et techniques de base de l'optimisation des performances Android, améliorant ainsi les performances et la stabilité des applications et offrant aux utilisateurs avec Offre une expérience plus soyeuse.

Il existe un large éventail de problèmes d'optimisation des performances Android. Voici quelques-uns des plus courants :

  1. Fuites de mémoire : des fuites de mémoire se produisent lorsqu'une application gère de manière incorrecte la mémoire, provoquant une utilisation excessive de la mémoire, voire provoquant le blocage de l'application.

  2. Optimisation de la mise en page : la mise en page est l'un des goulots d'étranglement en termes de performances les plus courants dans les applications, car une mise en page trop complexe peut entraîner un ralentissement ou un blocage de l'application.

  3. Optimisation des images : les images sont l'une des ressources les plus gourmandes en mémoire dans une application. Elles doivent donc être utilisées avec prudence et correctement compressées et mises en cache pour garantir les performances de l'application.

  4. Optimisation des requêtes réseau : les requêtes réseau peuvent prendre beaucoup de temps et de ressources dans une application, elles doivent donc être optimisées pour réduire le nombre de requêtes et augmenter la vitesse de réponse.

  5. Optimisation de la base de données : lorsqu'une application nécessite un accès important à la base de données, cela peut entraîner des problèmes de performances. Les performances des applications peuvent être améliorées en optimisant la conception de la base de données et en utilisant une mise en cache de base de données appropriée.

  6. Optimisation du multithreading : le multithreading peut améliorer les performances des applications, mais s'il est mal utilisé, il peut entraîner des blocages, des conflits de threads et d'autres problèmes.

  7. Optimisation de la mémoire : la mémoire est l'un des facteurs importants dans les performances des applications. Vous pouvez améliorer les performances des applications en libérant rapidement la mémoire qui n'est plus nécessaire et en évitant les allocations de mémoire inutiles.

  8. Optimisation du code : l'optimisation des structures de code et des algorithmes peut améliorer les performances des applications. Par exemple, utilisez des structures de données et des algorithmes plus rapides et plus efficaces pour améliorer la réactivité des applications.

  9. Optimisation de la sécurité : les problèmes de sécurité peuvent également avoir un impact négatif sur les performances de votre application. Vous pouvez améliorer la sécurité et les performances des applications en évitant les pratiques de codage dangereuses et en utilisant le chiffrement pour protéger vos données.

L'optimisation des performances d'Android se résume à des problèmes de mémoire, et l'optimisation au niveau de la mémoire ne concerne pas seulement les éléments d'optimisation conventionnels décrits dans la description, mais peut également optimiser davantage le nombre de lectures et d'écritures sur le disque, la synchronisation des données des pages du disque, etc.

1. Fuite de mémoire

Une fuite de mémoire fait référence à l'incapacité d'une application à libérer correctement les ressources mémoire qui ne sont plus utilisées pendant le fonctionnement, ce qui entraîne une augmentation continue de l'utilisation de la mémoire et finit par provoquer le blocage ou l'exécution lente de l'application.

Le principe de la fuite de mémoire

Le principe de fuite de mémoire Android signifie que lorsqu'une application utilise de la mémoire, en raison de problèmes ou d'erreurs de programmation, elle ne peut pas libérer la mémoire qui n'est plus utilisée, ce qui conduit finalement à une mémoire insuffisante dans le système, affectant la stabilité et les performances du système. .


Voici quelques causes courantes pouvant provoquer des fuites de mémoire Android :

Référence d'objet non libérée

Lorsque des objets sont créés, s'ils ne sont pas libérés correctement, ces objets occuperont de la mémoire jusqu'à la fermeture de l'application. Par exemple, lorsqu'une activité est détruite, si elle contient encore des références à d'autres objets, alors ces objets ne peuvent pas être recyclés par le garbage collector, ce qui entraîne une fuite de mémoire.

S'il y a une fuite de mémoire, alors les objets dans ces mémoires seront référencés et ne pourront pas être recyclés par le mécanisme de récupération de place. À ce stade, nous devons utiliser GCRoot pour identifier les objets et les références ayant subi une fuite de mémoire.

GCRoot est le nœud racine du mécanisme de récupération de place. Le nœud racine comprend la pile de machines virtuelles, la pile de méthodes locales, les références d'attributs statiques de classe dans la zone de méthode, les threads actifs, etc. Ces objets sont considérés comme des « objets vivants » par le garbage collection. mécanisme de collecte et ne sera pas recyclé.


Lorsque le mécanisme de récupération de place est exécuté,il démarrera à partir de GCRoot, parcourra toutes les références d'objet et marquera tous les objets vivants.Les objets non marqués sont des objets poubelles et seront recyclés.


Lorsqu'il y a une fuite de mémoire, le mécanisme de garbage collection ne peut pas recycler certains objets qui ne sont plus utilisés. Ces objets sont toujours référencés, formant des chaînes de référence de GCRoot aux objets ayant subi une fuite de mémoire. Ces objets ne seront pas recyclés, entraînant des fuites de mémoire.


En trouvant la chaîne de référence entre l'objet de fuite de mémoire et GCRoot, la source de la fuite de mémoire peut être localisée et le problème de fuite de mémoire peut être résolu. LeakCancry est implémenté via ce mécanisme. Certains GCRoots courants incluent :

  • Objet référencé dans la pile de la machine virtuelle (Variable Locale).

  • L'objet référencé par la propriété statique (Static Variable) dans la zone de méthode.

  • L'objet référencé par JNI.

  • Objet référencé par le thread Java (Thread).

  • Objets détenus par des verrous synchronisés en Java.

Fuite de mémoire causée par une classe interne anonyme

Les classes internes anonymes contiennent généralement des références à des classes externes. Si le cycle de vie de la classe externe est plus long que celui de la classe interne anonyme (correction, l'utilisation du cycle de vie n'est pas appropriée ici. Lorsque la classe externe est détruite, la classe interne la classe ne sera pas automatiquement détruite. , parce que la classe interne n'est pas une variable membre de la classe externe, ce sont simplement des objets créés dans la portée de la classe externe, donc le moment de la destruction de la classe interne et le moment de la destruction de la classe externe Les classes sont différentes, donc cela dépendra de l'existence ou non de l'objet correspondant. La référence détenue) empêchera la classe externe d'être recyclée, ce qui entraînera une fuite de mémoire.

Les variables statiques contiennent des références à l'activité ou au contexte

Si une variable statique contient une référence à une activité ou un contexte, alors ces activités ou contextes ne peuvent pas être recyclés par le ramasse-miettes, ce qui entraîne une fuite de mémoire.

Objet Curseur, Flux ou Bitmap non fermé

Si le programme ne ferme pas correctement les objets Cursor, Stream ou Bitmap lors de l'utilisation de ces objets, ces objets continueront à occuper la mémoire, entraînant des fuites de mémoire.

Ressources non libérées

Si le programme ne libère pas correctement les ressources système lors de leur utilisation, par exemple en ne fermant pas les connexions à la base de données, en ne libérant pas les ressources audio, etc., ces ressources continueront à occuper la mémoire, entraînant des fuites de mémoire.

Fuites de mémoire courantes

Fuites de mémoire causées par des références statiques

Lorsqu'un objet est détenu par une variable statique, même si l'objet n'est plus utilisé, il ne sera pas recyclé par le garbage collector, ce qui provoquera une fuite mémoire.

public class MySingleton {
    private static MySingleton instance;
    private Context context;

    private MySingleton(Context context) {
        this.context = context;
    }

    public static MySingleton getInstance(Context context) {
        if (instance == null) {
            instance = new MySingleton(context);
        }
        return instance;
    }
}

Dans le code ci-dessus, MySingleton contient une référence à un objet Context et MySingleton est une variable statique, ce qui signifie que même si l'objet n'est plus utilisé, il ne sera pas recyclé par le garbage collector.

Remarque : Si vous devez utiliser des variables statiques, veillez à les définir sur null lorsqu'elles ne sont pas nécessaires afin que la mémoire puisse être libérée à temps.

Fuite de mémoire causée par une classe interne anonyme

La classe interne anonyme contiendra implicitement une référence à la classe externe. Si la classe interne anonyme est conservée, la classe externe ne sera pas récupérée.

public class MyActivity extends Activity {
    private Button button;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        button = new Button(this);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // do something
            }
        });
        setContentView(button);
    }
}

La classe interne anonyme OnClickListener contient une référence à la classe externe MyActivity. Si le bouton n'est pas effacé avant la destruction de MyActivity, MyActivity ne sera pas récupéré. (Le bouton peut être considéré comme un objet défini par vous-même ici. La solution générale est de définir l'objet bouton comme vide)

Remarque : Lorsque l'activité est détruite, tous les objets contenant des références d'activité doivent être définis sur null.

Fuite de mémoire causée par le gestionnaire

Handler est un mécanisme de communication de thread couramment utilisé dans les applications Android. Si Handler est mal utilisé, cela entraînera des fuites de mémoire.

public class MyActivity extends Activity {
    private static final int MSG_WHAT = 1;
    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_WHAT:
                    // do something
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mHandler.sendEmptyMessageDelayed(MSG_WHAT, 1000 * 60 * 5);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 在Activity销毁时,应该将Handler的消息队列清空,以避免内存泄漏。
        mHandler.removeCallbacksAndMessages(null);
        }
}

Le gestionnaire contient une référence à l'activité. S'il y a des messages non traités dans la file d'attente des messages du gestionnaire avant que l'activité ne soit détruite, l'activité ne sera pas récupérée.


Remarque : lorsque l'activité est détruite, la file d'attente des messages du gestionnaire doit être effacée pour éviter les fuites de mémoire.

Fuite de mémoire causée par un objet Bitmap

Lorsqu'un objet Bitmap est créé, il occupera une grande quantité de mémoire. S'il n'est pas libéré à temps, cela provoquera une fuite de mémoire.

public class MyActivity extends Activity {
private Bitmap mBitmap;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // 加载一张大图
    mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.big_image);
}

@Override
protected void onDestroy() {
    super.onDestroy();
    // 释放Bitmap对象
    mBitmap.recycle();
    mBitmap = null;
}
}

Lorsque l'activité est détruite, l'objet Bitmap mBitmap doit être libéré à temps, sinon cela provoquera une fuite de mémoire.

Remarque : lors de l'utilisation d'un grand nombre d'objets Bitmap, les objets inutilisés doivent être recyclés à temps pour éviter les fuites de mémoire. De plus, vous pouvez envisager d'utiliser des bibliothèques de chargement d'images pour gérer les objets Bitmap, tels que Glide, Picasso, etc.

Fuites de mémoire causées par la non-fermeture des ressources

Lors de l'utilisation de certaines ressources système, telles que des fichiers, des bases de données, etc., si elles ne sont pas fermées à temps, des fuites de mémoire peuvent survenir. Par exemple:

public void readFile(String filePath) throws IOException {
    FileInputStream fis = null;
    try {
        fis = new FileInputStream(filePath);
        // 读取文件...
    } finally {
        if (fis != null) {
            try {
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

Dans le code ci-dessus, si l'objet FileInputStream n'est pas fermé à temps après la lecture du fichier, cela peut provoquer une fuite de mémoire.


Remarque : lors de l'utilisation de certaines ressources système, telles que des fichiers, des bases de données, etc., les objets concernés doivent être fermés à temps pour éviter les fuites de mémoire.


Pour éviter les fuites de mémoire, vous devez toujours faire attention lors de l'écriture du code, nettoyer rapidement les objets qui ne sont plus utilisés et vous assurer que les ressources mémoire sont libérées en temps opportun. En parallèle, vous pouvez utiliser certains outils pour détecter les problèmes de fuite de mémoire, comme Android Profiler, LeakCanary, etc.

Fuite de mémoire WebView

Lors de l'utilisation de WebView, s'il n'est pas publié à temps, cela peut provoquer une fuite de mémoire.

public class MyActivity extends Activity {
    private WebView mWebView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mWebView = findViewById(R.id.webview);
        mWebView.loadUrl("https://www.example.com");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 释放WebView对象
        if (mWebView != null) {
            mWebView.stopLoading();
            mWebView.clearHistory();
            mWebView.clearCache(true);
            mWebView.loadUrl("about:blank");
            mWebView.onPause();
            mWebView.removeAllViews();
            mWebView.destroy();
            mWebView = null;
        }
    }
}

Dans le code ci-dessus, lorsque l'activité est détruite, l'objet WebView doit être libéré à temps, sinon cela pourrait provoquer une fuite de mémoire.

Remarque : lorsque vous utilisez WebView, vous devez libérer l'objet WebView à temps. Vous pouvez appeler la méthode destroy de WebView lorsque l'activité est détruite. En même temps, vous devez effacer l'historique, le cache, etc. de WebView pour vous assurer que tout les ressources sont libérées.

Outils de surveillance

  1. Outil de surveillance de la mémoire : Android Studio fournit un outil de surveillance de la mémoire qui peut surveiller l'utilisation de la mémoire des applications en temps réel pendant le processus de développement, aidant ainsi les développeurs à découvrir les fuites de mémoire en temps opportun.

  2. DDMS : l'outil DDMS du SDK Android peut surveiller les processus et les threads des appareils ou émulateurs Android, y compris l'utilisation de la mémoire, les traces de pile et d'autres informations, et peut être utilisé pour diagnostiquer les fuites de mémoire.

  3. MAT : MAT (Memory Analyser Tool) est un outil d'analyse de mémoire basé sur Eclipse qui peut analyser l'utilisation de la mémoire tas des applications et identifier et localiser les fuites de mémoire.

  4. Matrix de Tencent est également un très bon projet open source et son utilisation est recommandée à tous.

2. Résumé

Une fuite de mémoire signifie que certains objets ou ressources du programme ne sont pas libérés correctement, ce qui entraîne une utilisation croissante de la mémoire, ce qui peut éventuellement entraîner des pannes d'application ou un fonctionnement lent du système.


Les problèmes courants de fuite de mémoire incluent :

  1. Fuites de mémoire causées par la conservation prolongée d’objets Activity ou Fragment ;

  2. Fuites de mémoire causées par des classes internes anonymes et des classes internes non statiques ;

  3. Fuite de mémoire provoquée par WebView contenant un objet Activity ;

  4. Fuites de mémoire causées par la conservation des objets ressources en mode singleton ;

  5. Fuites de mémoire causées par la non-fermeture des ressources ;

  6. Fuites de mémoire causées par des variables statiques contenant des objets Context ;

  7. Fuite de mémoire provoquée par le gestionnaire détenant une référence de classe externe ;

  8. Fuites de mémoire causées par Bitmap occupant une grande quantité de mémoire ;

  9. Fuites de mémoire causées par des singletons contenant de grandes quantités de données.

Pour éviter les problèmes de fuite de mémoire, nous pouvons prendre les mesures suivantes :

  1. Libérez rapidement l'objet Activity ou Fragment ;

  2. Évitez les classes internes anonymes et les classes internes non statiques ;

  3. Lorsque vous utilisez WebView, appelez la méthode destroy rapidement ;

  4. Évitez de conserver des objets ressources pendant une longue période en mode singleton ;

  5. Fermez rapidement les objets ressources ;

  6. Évitez les variables statiques contenant des objets Context ;

  7. Évitez que Handler détienne des références de classe externes ;

  8. Lorsque vous utilisez Bitmap, libérez de la mémoire à temps ;

  9. Évitez les singletons contenant de grandes quantités de données.

Ce qui précède est un résumé de l'optimisation des performances Android. Les scénarios de fuite de mémoire sont différents et les méthodes d'optimisation ne sont pas uniques. Tout le monde est invité à en discuter ensemble.

Je suppose que tu aimes

Origine blog.csdn.net/weitao_666/article/details/132336906
conseillé
Classement