Résumé de 8 types de fuites de mémoire en Java

Étant donné que Java JVM introduit un mécanisme de récupération de place, le récupérateur de mémoire recyclera automatiquement les objets qui ne sont plus utilisés. Quiconque comprend le mécanisme de recyclage de la machine virtuelle Java sait que la machine virtuelle Java utilise des algorithmes de comptage de références et d’analyse d'accessibilité pour déterminer si un objet n'est plus utilisé. L' essence d'un objet est de déterminer si un objet est toujours référencé . Donc, dans ce cas, en raison de différentes implémentations de code, il y aura de nombreux types de problèmes de fuite de mémoire (la JVM croit à tort que l'objet est toujours en référence et ne peut pas être recyclé, ce qui provoque des fuites de mémoire).

1. Classes de collection statiques , telles que HashMap, LinkedList, etc. Si ces conteneurs sont statiques, leur cycle de vie est cohérent avec le programme et les objets du conteneur ne peuvent pas être libérés avant la fin du programme, ce qui entraîne des fuites de mémoire. En termes simples, les objets de longue durée renferment des références à des objets de courte durée. Bien que les objets de courte durée ne soient plus utilisés, ils ne peuvent pas être recyclés car les objets de longue durée conservent leurs références.

2, les différentes connexions, telles que la connexion à la base de données, la connexion réseau et les connexions IO . Lors du fonctionnement de la base de données, vous devez d'abord établir une connexion avec la base de données. Lorsqu'elle n'est plus utilisée, vous devez appeler la méthode close pour libérer la connexion avec la base de données. Ce n'est qu'après la fermeture de la connexion que le garbage collector récupérera l'objet correspondant. Sinon, si dans le processus d'accès à la base de données, la connexion, l'instruction ou le ResultSet n'est pas explicitement fermé, cela entraînera l'impossibilité de recycler un grand nombre d'objets, provoquant des fuites de mémoire.

3. Portée déraisonnable des variables . D'une manière générale, la portée de la définition d'une variable est supérieure à la portée de son utilisation, ce qui est susceptible de provoquer des fuites de mémoire. En revanche, si l'objet n'est pas défini sur null dans le temps, il est susceptible de provoquer une fuite de mémoire.

 

public class UsingRandom {

		private String msg;

		public void receiveMsg(){
		
		readFromNet();// 从网络中接受数据保存到msg中
		
		saveDB();// 把msg保存到数据库中

}

}

Comme dans le pseudo code ci-dessus , le message reçu est enregistré dans la variable msg via la méthode readFromNet, puis la méthode saveDB est appelée pour enregistrer le contenu de msg dans la base de données. À ce stade, msg est inutile, en raison de la durée de vie cycle de msg et durée de vie de l'objet Le cycle est le même, et msg ne peut pas être récupéré à ce moment, provoquant ainsi une fuite de mémoire.

En fait, cette variable msg peut être placée dans la méthode receiveMsg. Lorsque la méthode est épuisée, le cycle de vie de msg est également terminé et il peut être recyclé à ce moment. Il existe un autre moyen, après avoir utilisé msg, de définir msg sur null, afin que le garbage collector récupère également l'espace mémoire de msg.

4. La classe interne contient la classe externe . Si une méthode d'un objet d'instance d'une classe externe renvoie un objet d'instance d'une classe interne, l'objet de classe interne est référencé à long terme, même si l'objet d'instance de classe externe n'est plus utilisé, mais à cause de la classe interne La classe contient un objet d'instance d'une classe externe, et cet objet de classe externe ne sera pas récupéré, ce qui entraînera également des fuites de mémoire.

5. Modifiez la valeur de hachage . Lorsqu'un objet est stocké dans la collection HashSet, les champs de l'objet qui participent au calcul de la valeur de hachage ne peuvent pas être modifiés. Sinon, la valeur de hachage modifiée de l'objet est stockée à l'origine dans le HashSet collection. La valeur de hachage est différente dans le temps moyen. Dans ce cas, même si la méthode contains utilise la référence actuelle de l'objet comme paramètre pour récupérer l'objet dans la collection HashSet, elle renverra le résultat que l'objet ne peut pas être trouvé, ce qui entraînera également Impossible de supprimer l'objet actuel séparément de la collection HashSet, provoquant des fuites de mémoire

6. Prenons un exemple - voyez si vous pouvez trouver la fuite de mémoire


import java.util.Arrays;

public class Stack {
    private Object[] elements;
    private int size = 0;
    private static final int DEFAULT_INITIAL_CAPACITY = 16;

    public Stack() {
        elements = new Object[DEFAULT_INITIAL_CAPACITY];
    }

    public void push(Object e) {
        ensureCapacity();
        elements[size++] = e;
    }

    public Object pop() {
        if (size == 0)
            throw new EmptyStackException();
        return elements[--size];
    }

    private void ensureCapacity() {
        if (elements.length == size)
            elements = Arrays.copyOf(elements, 2 * size + 1);
    }
}

6.1 Analyse des causes

Il n'y a pas d'erreur évidente dans le programme ci-dessus, mais ce programme a une fuite de mémoire. Avec l'augmentation de l'activité du GC ou l'augmentation continue de l'utilisation de la mémoire, les performances du programme seront réduites. Dans les cas graves, des fuites de mémoire peuvent être causées Il y a relativement peu de pannes.
Le principal problème du code est la fonction pop, qui est représentée ci-dessous par cette icône.
En supposant que la pile continue de croître, comme le montre la figure ci-dessous après la croissance,
Écrivez la description de l'image ici
lorsqu'un grand nombre d'opérations pop sont effectuées, gc ne sera pas libéré car la référence n'est pas effacée, comme le montre l'image
Écrivez la description de l'image ici

On peut voir à partir de la figure ci-dessus que si la pile se développe d'abord, puis se rétrécit, les objets sortis de la pile ne seront pas traités comme un ramasse-miettes. Même si le programme n'utilise plus ces files d'attente dans la pile, elles ne seront pas collectées ., Étant donné que la référence de cet objet est toujours stockée dans la pile, communément appelée référence expirée, cette fuite de mémoire est très masquée.

1.2 Solution

public Object pop() {
    if (size == 0)
    throw new EmptyStackException();
    Object result = elements[--size];
    elements[size] = null;
    return result;
}

Une fois les références expirées, effacez ces références et rendez les références vides.
Écrivez la description de l'image ici

7. Fuites de cache

Une autre source courante de fuites de mémoire est le cache. Une fois que vous avez mis une référence d'objet dans le cache, il est facile de l'oublier. Pour ce problème, WeakHashMap peut être utilisé pour représenter le cache. La caractéristique de ce type de carte est qu'il a un key S'il n'y a pas d'autre référence à cette clé, cette carte supprimera automatiquement cette valeur

7.1 Exemple de code

package com.ratel.test;

/**
 * @业务描述:
 * @package_name: com.ratel.test
 * @project_name: ssm
 * @author: [email protected]
 * @create_time: 2019-04-18 20:20
 * @copyright (c) ratelfu 版权所有
 */
import java.util.HashMap;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.TimeUnit;

public class MapTest {
    static Map wMap = new WeakHashMap();
    static Map map = new HashMap();
    public static void main(String[] args) {
        init();
        testWeakHashMap();
        testHashMap();
    }



    public static void init(){
        String ref1= new String("obejct1");
        String ref2 = new String("obejct2");
        String ref3 = new String ("obejct3");
        String ref4 = new String ("obejct4");
        wMap.put(ref1, "chaheObject1");
        wMap.put(ref2, "chaheObject2");
        map.put(ref3, "chaheObject3");
        map.put(ref4, "chaheObject4");
        System.out.println("String引用ref1,ref2,ref3,ref4 消失");

    }
    public static void testWeakHashMap(){

        System.out.println("WeakHashMap GC之前");
        for (Object o : wMap.entrySet()) {
            System.out.println(o);
        }
        try {
            System.gc();
            TimeUnit.SECONDS.sleep(20);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("WeakHashMap GC之后");
        for (Object o : wMap.entrySet()) {
            System.out.println(o);
        }
    }
    public static void testHashMap(){
        System.out.println("HashMap GC之前");
        for (Object o : map.entrySet()) {
            System.out.println(o);
        }
        try {
            System.gc();
            TimeUnit.SECONDS.sleep(20);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("HashMap GC之后");
        for (Object o : map.entrySet()) {
            System.out.println(o);
        }
    }

}
/** 结果
 String引用ref1,ref2,ref3,ref4 消失
 WeakHashMap GC之前
 obejct2=chaheObject2
 obejct1=chaheObject1
 WeakHashMap GC之后
 HashMap GC之前
 obejct4=chaheObject4
 obejct3=chaheObject3
 Disconnected from the target VM, address: '127.0.0.1:51628', transport: 'socket'
 HashMap GC之后
 obejct4=chaheObject4
 obejct3=chaheObject3
 **/

  • Écrivez la description de l'image ici
    Le code et l'illustration ci-dessus montrent comment WeakHashMap libère automatiquement l'objet de cache. Lorsque la fonction init est exécutée, la chaîne de variable locale fait référence à lowd1, lowd2, d1, d2 disparaîtra. À ce stade, seule la référence à l'objet chaîne dans le fichier statique map est enregistrée., Vous pouvez voir qu'après avoir appelé gc, le hashmap n'est pas recyclé, mais le cache de WeakHashmap est recyclé.

8. Auditeur et rappel

Les écouteurs et autres rappels constituent la troisième source courante de fuites de mémoire. Si le client enregistre un rappel dans l'API que vous implémentez, mais ne l'annule pas, il s'accumulera. La meilleure façon de garantir que les rappels sont immédiatement traités comme un garbage collection est de ne sauvegarder que leurs références, par exemple, de les enregistrer en tant que clés dans WeakHashMap.

Je suppose que tu aimes

Origine blog.csdn.net/qq_26896085/article/details/115276022
conseillé
Classement