Dans une interview, on m'a demandé comment détecter les fuites de mémoire en Java?


Je ne sais pas comment répondre à cette question. Au lieu de cela, je leur ai dit que je n'avais vu aucun code/situation pratique dans une application Web qui pourrait provoquer une fuite de mémoire. Je lui ai également dit que s'il y avait trop d'objets en cours de création et que ces objets sortaient de la portée, le GC se chargerait de récupérer la mémoire.

Mes questions sont (1) Ma réponse était-elle assez bonne ? (2) Pouvez-vous me donner un exemple pratique de la fuite de mémoire Java dans un Web et / ou non-Web de l'environnement?

Merci

Author: shortduck, 2018-06-15

3 answers

Bon sujet!

Vous devez d'abord surveiller la consommation de mémoire Java.

La façon la plus simple de le faire est d'utiliser l'utilitaire jstat fourni avec chaque JVM.

jstat -gcutil <process_id> <timeout>

Il rapportera la consommation de mémoire pour chaque génération (Jeune, Âgé et Vieux) et les temps de collecte des ordures (Jeune et Plein).

Dès que vous constatez que la récupération de place complète est exécutée trop souvent et prend trop de temps, vous pouvez supposer que l'application fuit la mémoire.

Alors vous avez besoin pour créer un vidage de mémoire à l'aide de l'utilitaire jmap:

jmap -dump:live,format=b,file=heap.bin <process_id>

Ensuite, vous devez analyser le tas.fichier bin avec Analyseur de mémoire, Analyseur de mémoire Eclipse (MAT) par exemple.

MAT analysera la mémoire et vous fournira des informations suspectes sur les fuites de mémoire.

 1
Author: Pavel Molchanov, 2018-06-15 19:13:55

Une fuite de mémoire est une situation où vous continuez à conserver la mémoire allouée dont vous n'avez plus besoin et que vous n'avez plus l'intention d'utiliser.

Prenons l'exemple suivant:

public class LeakMemory {
    private static final List<String> LEAK = new ArrayList<>();

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        System.out.println("What is your name? ");
        while (in.hasNext()) {
            name = in.next();
            System.out.println("Hi " + name);
            LEAK.add(name);
        }
    }
}

La liste des FUITES augmente à chaque itération, et il n'y a aucun moyen de la libérer, mais elle n'est jamais utilisée. C'est une fuite.

 0
Author: amrender singh, 2018-06-15 19:07:04

Par la définition normale d'une fuite de mémoire , Java ne les a pas en raison de la récupération de place. Si, cependant, nous élargissons un peu la définition aux "Objets dont le programme n'a plus besoin, mais qui ne sont pas à collectionner", alors je peux penser à deux scénarios où de telles "fuites" pourraient survenir.


Scénario 1: enregistrer tous les objets d'une classe jamais créée

Cet exemple a un goût artificiel et est souvent vu dans le cadre d'un exercice. Supposons que nous souhaitions stocker chaque instance d'une certaine classe jamais créée. Cela peut être réalisé via un colleciton statique:

public class RecordMe {
  private static final List<RecordMe> created = new ArrayList<RecordMe>();
  ...
  private final int someValue;

  private RecordMe(final int someValue) {
    this.someValue = someValue;
  }

  public static RecordMe of(final int someValue) {
    RecordMe me = new RecordMe(someValue);
    created.add(me);
    return me;
  }

  public static List<RecordMe> instances() {
    return Collections.unmodifiableList(created);
  }
}

Dès qu'une instance de RecordMe est créée, elle ne peut jamais être récupérée car elle sera toujours référencée dans la liste statique.

La solution serait de vérifier la liste avant de créer une nouvelle instance de RecordMe ou de l'utilisation List<WeakReference<RecordMe>> (pour nettoyer cette liste de temps à autre).


Scénario 2: Fuites à travers l'intérieur les classes

Comme nous le savons, une classe interne non staitc contient une référence implicite à l'objet à partir duquel elle a été créée. Jetons un coup d'oeil sur un exemple extrême.

public class MemoryTest {
  // data has a size of a little over 512 MB.
  private final byte[] data = new byte[1024 * 1024 * 512];
  private final Field field;

  public class Field {
  }

  public MemoryTest() {
    this.field = new Field();
  }

  public Field getField() {
    return this.field;
  }

  public static void main(String... args) {
    MemoryTest test = new MemoryTest();
    Field fieldOne = test.getField();
    test = null;
    test = new MemoryTest();
  }
}

Si nous exécutons ce code avec java -Xmx800m MemoryTest, il va jeter un OutOfMemoryException. Les exemples de ces tailles sont irréalistes dans le réel, mais dans des tailles plus petites et avec suffisamment d'instances, cela peut également entraîner des problèmes. Prenez, par exemple, Java HashMap-mise en œuvre. Méthode keySet() renvoie une instance d'un, intérieur de la classe. Tant que l'on détient des instances à ces classes internes, le HashMap ne peut pas être collecté.

 0
Author: Turing85, 2018-06-15 19:38:52