Maison  >  Article  >  Quelles sont les causes et les solutions des fuites de mémoire

Quelles sont les causes et les solutions des fuites de mémoire

醉折花枝作酒筹
醉折花枝作酒筹original
2021-05-17 16:10:3329709parcourir

Les raisons et les solutions sont : 1. Utilisez des classes internes statiques pour éviter les fuites de mémoire causées par les threads ; 2. Utilisez convertView en cache pour construire un adaptateur afin d'éviter les fuites de mémoire causées par ListView ; clear Les éléments de la collection sont définis sur null pour éviter les fuites de mémoire dans le conteneur de collection.

Quelles sont les causes et les solutions des fuites de mémoire

L'environnement d'exploitation de ce tutoriel : système Windows 7, ordinateur Dell G3.

Causes courantes des fuites de mémoire

1. Fuites de mémoire causées par des singletons

En raison du singleton La statique La nature de l'instance rend son cycle de vie aussi long que le cycle de vie de l'application. Si un objet n'est plus nécessaire et que l'objet singleton contient toujours une référence à l'objet, l'objet ne peut pas être recyclé normalement, ce qui entraîne une fuite de mémoire. .

Exemple : Empêcher les instances singleton de provoquer des fuites de mémoire

// 使用了单例模式
public class AppManager {
    private static AppManager instance;
    private Context context;
    private AppManager(Context context) {
        this.context = context;
    }
    public static AppManager getInstance(Context context) {
        if (instance != null) {
            instance = new AppManager(context);
        }
        return instance;
    }
}

2 Fuites de mémoire causées par des classes internes non statiques créant des instances statiques

Par exemple. , Parfois, nous pouvons démarrer des activités fréquemment. Afin d'éviter de créer à plusieurs reprises les mêmes ressources de données, l'écriture suivante peut apparaître :

  public class MainActivity extends AppCompatActivity {

    private static TestResource mResource = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        if(mResource == null){
            mResource = new TestResource();
        }
        //...
    }
    
    class TestResource {
    //...
    }
}

3. Fuite de mémoire causée par le gestionnaire

Exemple : Créez un objet statique d'une classe interne anonyme

public class MainActivity extends AppCompatActivity {

    private final Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            // ...
        }
    };

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

        new Thread(new Runnable() {
            @Override
            public void run() {
                // ...
                handler.sendEmptyMessage(0x123);
            }
        });
    }
}

1 Du point de vue Android

Lorsqu'une application Android démarre, le thread principal de l'application crée automatiquement un objet Looper et. la MessageQueue qui lui est associée. Lorsqu’un objet Handler est instancié dans le thread principal, il sera automatiquement associé au MessageQueue du thread principal Looper. Tous les messages envoyés à MessageQueue contiendront une référence au gestionnaire, donc Looper rappellera la méthode handleMessage() du handle en conséquence pour traiter le message. Tant qu'il y a des messages non traités dans MessageQueue, le Looper continuera à les supprimer et à les transmettre au gestionnaire pour traitement. De plus, l’objet Looper du thread principal accompagnera tout le cycle de vie de l’application.

2. Perspective Java

En Java, les classes internes non statiques et les classes internes anonymes contiendront potentiellement des références aux classes externes auxquelles elles appartiennent, mais pas les classes internes statiques.

En analysant l'exemple ci-dessus, lorsque MainActivity se termine, le message non traité contient une référence au gestionnaire, et le gestionnaire contient une référence à la classe externe à laquelle il appartient, qui est MainActivity. Cette relation de référence restera jusqu'à ce que le message soit traité, ce qui empêche MainActivity d'être recyclé par le garbage collector, provoquant une fuite de mémoire.

Solution : Séparez la classe Handler ou utilisez une classe interne statique pour éviter les fuites de mémoire.

4. Fuites de mémoire causées par les threads

Exemple : AsyncTask et Runnable

public class MainActivity extends AppCompatActivity {

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

        new Thread(new MyRunnable()).start();
        new MyAsyncTask(this).execute();
    }

    class MyAsyncTask extends AsyncTask<Void, Void, Void> {

        // ...

        public MyAsyncTask(Context context) {
            // ...
        }

        @Override
        protected Void doInBackground(Void... params) {
            // ...
            return null;
        }

        @Override
        protected void onPostExecute(Void aVoid) {
            // ...
        }
    }

    class MyRunnable implements Runnable {
        @Override
        public void run() {
            // ...
        }
    }
}

AsyncTask et Runnable utilisent tous deux des classes internes anonymes, ils seront alors retenus une référence implicite à l’activité dans laquelle il réside. Si la tâche n'est pas terminée avant la destruction de l'activité, les ressources mémoire de l'activité ne seront pas recyclées, provoquant une fuite de mémoire.

Solution : Séparez les classes AsyncTask et Runnable ou utilisez des classes internes statiques pour éviter les fuites de mémoire.

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

Pour les ressources telles que BraodcastReceiver, ContentObserver, File, Cursor, Stream, Bitmap, etc., elles devraient l'être. détruites à temps lorsque l'activité est détruite. Fermez ou déconnectez-vous, sinon ces ressources ne seront pas recyclées, provoquant des fuites de mémoire.

1) Par exemple, un BraodcastReceiver est enregistré dans l'activité, mais le BraodcastReceiver n'est pas désenregistré une fois l'activité terminée.

2) Les objets ressources tels que Cursor, Stream, File, etc. utilisent souvent certains tampons lorsque nous ne les utilisons pas, nous devons les fermer à temps afin que leurs tampons puissent récupérer de la mémoire à temps. Leurs tampons existent non seulement au sein de la machine virtuelle Java, mais également en dehors de la machine virtuelle Java. Si nous définissons simplement ses références sur null sans les fermer, des fuites de mémoire se produiront souvent.

3) Lorsqu'un objet ressource n'est pas utilisé, sa fonction close() doit être appelée pour le fermer, puis définie sur null. Nous devons nous assurer que nos objets ressources sont fermés à la fin de notre programme.

4) Appelez recycle() pour libérer de la mémoire lorsque l'objet Bitmap n'est plus utilisé. Les bitmaps postérieurs à la version 2.3 ne devraient plus avoir besoin d'être recyclés manuellement, car la mémoire se trouve déjà dans la couche Java.

6. Fuites de mémoire provoquées lors de l'utilisation de ListView

Initialement, ListView instanciera un certain nombre d'objets View à partir de BaseAdapter en fonction de la disposition actuelle de l'écran, et ListView mettra en cache ces objets View. Lorsque le ListView défile vers le haut, l'objet View de l'élément initialement situé en haut sera recyclé puis utilisé pour construire l'élément qui apparaît en dessous. Ce processus de construction est complété par la méthode getView(). Le deuxième paramètre formel convertView de getView() est l'objet View de l'élément mis en cache (s'il n'y a pas d'objet View dans le cache lors de l'initialisation, convertView est nul).

Lors de la construction de l'adaptateur, le convertView mis en cache n'est pas utilisé.

Solution : utilisez le convertView mis en cache lors de la construction de l'adaptateur.

7. Fuite de mémoire dans le conteneur de collecte

Nous ajoutons généralement des références d'objet au conteneur de collection (comme ArrayList). Lorsque nous n'avons pas besoin de l'objet, nous n'effaçons pas ses références de la collection, donc la collection deviendra de plus en plus grande. Si cette collection est statique, la situation est encore plus grave.

Solution : avant de quitter le programme, effacez les éléments de la collection, puis définissez-les sur null, puis quittez le programme.

8. Fuite provoquée par WebView

Quand on n'utilise plus l'objet WebView, il faut appeler sa fonction destroy() pour le détruire et libérer la mémoire qu'il occupe . , sinon la mémoire qu'elle occupe depuis longtemps ne peut pas être recyclée, provoquant une fuite de mémoire.

Solution : ouvrez un autre processus pour WebView et communiquez avec le thread principal via AIDL. Le processus dans lequel se trouve WebView peut choisir le moment approprié pour la destruction en fonction des besoins de l'entreprise, obtenant ainsi une libération complète de la mémoire.

Pour plus de connaissances liées à l'informatique, veuillez visiter la rubrique FAQ !

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn