web-dev-qa-db-fra.com

Comprendre Java Gestion de la mémoire

Les programmeurs Java savent que JVM exécute un Garbage Collector et System.gc () serait simplement une suggestion à JVM pour exécuter un Garbage Collector. Ce n'est pas nécessairement que si nous utilisons System.gc (), il exécuterait immédiatement le GC.

Veuillez me corriger si je comprends mal le garbage collector de Java.

Existe-t-il/existe-t-il d'autres moyens de gérer la mémoire que de s'appuyer sur le garbage collector de Java?
Si vous avez l'intention de répondre à la question par une sorte de pratique de programmation qui aiderait à gérer la mémoire, veuillez le faire.

14

La chose la plus importante à retenir à propos de Java est "annuler" votre référence.

Seuls les objets non référencés doivent être récupérés.

Par exemple, les objets dans le code suivant ne sont jamais récupérés et votre mémoire sera pleine juste pour ne rien faire.

List objs = new ArrayList();
for (int i = 0; i  < Integer.MAX_VALUE; i++) objs.add(new Object());

Mais si vous ne faites pas référence à ces objets ... vous pouvez boucler autant que vous le souhaitez sans problème de mémoire.

List objs = new ArrayList();
for (int i = 0; i  < Integer.MAX_VALUE; i++) new Object();

Donc, quoi que vous fassiez, assurez-vous de supprimer la référence à l'objet qui n'est plus utilisé (définissez la référence sur null ou effacez la collection).

Il est préférable de laisser la machine virtuelle Java décider du moment où le garbage collector s'exécutera. À moins que votre programme ne soit sur le point de commencer à faire des choses qui utilisent beaucoup de mémoire et qui sont critiques en termes de vitesse, vous pouvez suggérer à JVM d'exécuter GC avant d'entrer, car vous obtiendrez probablement la mémoire collectée et la mémoire supplémentaire pour continuer. Sinon, je ne vois personnellement aucune raison d'exécuter System.gc().

J'espère que cette aide.

15
NawaMan

Voici un petit résumé que j'ai écrit à l'époque (je l'ai volé sur un blog, mais je ne me souviens pas d'où - donc aucune référence, désolé)

  1. Il n'y a aucun moyen manuel de faire le ramasse-miettes en Java.
  2. Java Heap est divisé en trois générations pour le ramassage des ordures. Ce sont la jeune génération, la tenure ou l'ancienne génération, et la région de Perm.
  3. De nouveaux objets sont créés dans la jeune génération et ensuite déplacés vers l'ancienne génération.
  4. Le pool de chaînes est créé dans la zone Perm du tas, le garbage collection peut se produire dans l'espace perm mais dépend de JVM à JVM.
  5. La collecte des ordures mineures est utilisée pour déplacer un objet de l'espace Eden vers l'espace Survivor 1 et Survivor 2, et la collecte Major permet de déplacer un objet de la génération jeune à la génération permanente.
  6. Chaque fois que la récupération de place majeure se produit dans l'application, les threads s'arrêtent pendant cette période, ce qui réduit les performances et le débit de l'application.
  7. Il y a peu d'améliorations des performances a été appliquée dans la récupération de place dans Java 6 et nous utilisons généralement JRE 1.6.20 pour exécuter notre application.
  8. Options de ligne de commande JVM -Xms et -Xmx est utilisé pour configurer le démarrage et la taille maximale pour Java Heap. Le rapport idéal de ce paramètre est de 1: 1 ou 1: 1,5 en fonction de mon expérience, par exemple, vous pouvez avoir soit tous les deux –Xmx et –Xms comme 1 Go ou –Xms 1,2 Go et 1,8 Go.

Options de ligne de commande: -Xms:<min size> -Xmx:<max size>

14
aviad

Juste pour ajouter à la discussion: Garbage Collection n'est pas la seule forme de gestion de la mémoire en Java .

Dans le passé, des efforts ont été faits pour éviter le GC dans Java lors de l'implémentation de la gestion de la mémoire (voir Spécification en temps réel pour Java ( RTSJ) ). Ces efforts ont été principalement consacrés à la programmation en temps réel et intégrée dans Java pour laquelle GC n'était pas adapté - en raison de la surcharge de performances ou de la latence introduite par GC).

Les caractéristiques du RTSJ

  • Gestion de la mémoire immortelle et étendue - voir ci-dessous pour des exemples.
  • Le GC et la mémoire immortelle/étendue peuvent coexister avec une seule application
  • RTSJ nécessite une JVM spécialement modifiée.

Avantages RTSJ:

  • faible latence, pas de pause du GC
  • offre des performances prévisibles capables de répondre aux exigences du système en temps réel

Pourquoi RTSJ a échoué/n'a pas eu un grand impact:

  • Le concept de mémoire étendue est difficile à programmer, sujet aux erreurs et difficile à apprendre.
  • Les avancées dans les algorithmes de GC en temps réel ont réduit le temps de pause du GC de telle manière que les GC en temps réel ont remplacé le RTSJ dans la plupart des applications en temps réel. Cependant, les mémoires de portée sont toujours utilisées dans des endroits où aucune latence n'est tolérée.

Exemple de code de mémoire étendue (tiré de n exemple d'utilisation de la mémoire étendue ):

import javax.realtime.*;
public class ScopedMemoryExample{

    private LTMemory myMem;

    public ScopedMemoryExample(int Size) {

       // initialize memory
       myMem = new LTMemory(1000, 5000); 
    }

public void periodicTask() {

  while (true)) {
    myMem.enter(new Runnable() {
        public void run() {
          // do some work in the SCOPED MEMORY
          new Object();
          ...
          // end of the enter() method, the scoped Memory is emptied.  
        }
    });
  }


}
}

Ici, une implémentation ScopedMemory appelée LTMemory est préallouée. Ensuite, un thread entre dans la mémoire de portée, alloue les données temporaires qui sont nécessaires uniquement pendant le temps du calcul. Après la fin du calcul, le thread quitte la mémoire de portée qui fait immédiatement vider tout le contenu de la mémoire Scoped spécifique. Aucune latence introduite, effectuée en temps constant, par ex. temps prévisible, aucun GC n'est déclenché.

7
Aleš

Vous ne pouvez pas éviter le garbage collection si vous utilisez Java. Peut-être existe-t-il des implémentations JVM obscures, mais je n'en connais pas.

Une JVM correctement réglée ne devrait pas nécessiter de conseils System.gc () pour fonctionner correctement. Le réglage exact dont vous auriez besoin dépend fortement de ce que fait votre application, mais d'après mon expérience, j'active toujours l'option concurrent-mark-and-sweep avec l'indicateur suivant: -XX:+UseConcMarkSweepGC. Cet indicateur permet à la JVM de tirer parti des cœurs supplémentaires de votre CPU pour nettoyer la mémoire morte sur un thread d'arrière-plan. Cela permet de réduire considérablement la durée de pause de votre programme lors de la récupération de place.

4
cambecc

D'après mon expérience, en Java vous devez vous fier à la gestion de la mémoire fournie par JVM elle-même.

Le point sur lequel je me concentrerais dans cette rubrique est de le configurer d'une manière acceptable pour votre cas d'utilisation. Peut-être que vérifier/comprendre les options de réglage JVM serait utile: http://docs.Oracle.com/cd/E15523_01/web.1111/e13814/jvm_tuning.htm

4
Peter Butkovic

Vous avez raison de dire que System.gc() est une demande au compilateur et non une commande. Mais en utilisant le programme ci-dessous, vous pouvez vous assurer que cela se produit.

import Java.lang.ref.WeakReference;

public class GCRun {

    public static void main(String[] args) {

        String str = new String("TEMP");
        WeakReference<String> wr = new WeakReference<String>(str);
        str = null;
        String temp = wr.get();
        System.out.println("temp -- " + temp);
        while(wr.get() != null) {
            System.gc();
        }
    }
}
3
Ishan Aggarwal

Eh bien, le GC est toujours là - vous ne pouvez pas créer d'objets qui sont hors de sa portée (sauf si vous utilisez des appels natifs ou allouez un tampon d'octets direct, mais dans ce dernier cas, vous n'avez pas vraiment d'objet, juste un tas d'octets). Cela dit, il est certainement possible de contourner le GC en réutilisant des objets. Par exemple, si vous avez besoin d'un tas d'objets ArrayList, vous pouvez simplement créer chacun comme vous en avez besoin et laisser le GC gérer la gestion de la mémoire; ou vous pouvez appeler list.clear() sur chacun après l'avoir terminé, et le mettre dans une file d'attente où quelqu'un d'autre peut l'utiliser.

Les meilleures pratiques standard sont de pas faire ce genre de réutilisation sauf si vous avez une bonne raison de le faire (c.-à-d., Vous avez profilé et vu que les allocations + GC sont un problème, et que la réutilisation des objets corrige ce problème) . Cela conduit à un code plus compliqué, et si vous vous trompez, cela peut en fait rendre le travail du GC plus difficile (à cause de la façon dont le GC suit les objets).

3
yshavit

Fondamentalement, l'idée de Java est que vous ne devez pas gérer la mémoire, sauf en utilisant "new" pour allouer de nouveaux objets et vous assurer qu'il n'y a plus de références aux objets lorsque vous en avez fini avec eux.

Tout le reste est délibérément laissé au Runtime Java et est - aussi délibérément - défini aussi vaguement que possible pour permettre aux concepteurs de la JVM la plus grande liberté de le faire efficacement.

Pour utiliser une analogie: Votre système d'exploitation gère pour vous des zones nommées d'espace disque (appelées "fichiers"). Y compris la suppression et la réutilisation de zones que vous ne souhaitez plus utiliser. Vous ne contournez pas ce mécanisme mais le laissez au système d'exploitation

Vous devez vous concentrer sur l'écriture d'un code clair et simple et vous assurer que vos objets sont correctement utilisés. Cela donnera à la JVM les meilleures conditions de travail possibles.

3

Je suggère de jeter un œil aux tutoriels suivants et à leur contenu

Il s'agit d'une série de didacticiels en quatre parties pour connaître les bases de la récupération de place dans Java:

  1. Présentation de Java Garbage Collection

  2. Comment Java Garbage Collection fonctionne?

  3. Types de Java Garbage Collectors

  4. Surveillance et analyse Java Garbage Collection

J'ai trouvé ce tutoriel très utile.

2
Tasawar Hussain

"Nullifier" la référence lorsqu'elle n'est pas requise est le meilleur moyen de rendre un objet éligible pour la collecte des ordures.

Il existe 4 façons de récupérer un objet. 1. pointez la référence sur null, une fois qu'elle n'est plus requise.

String s = new String("Java");

Une fois que cette chaîne n'est pas requise, vous pouvez la pointer sur null.

s = null;

Par conséquent, les s seront éligibles pour la collecte des ordures.

  1. pointer un objet vers un autre, de sorte que les deux références pointent vers le même objet et que l'un des objets soit éligible au GC.

    String s1 = new String ("Java");

    String s2 = new String ("C++");

À l'avenir, si s2 doit également pointer vers s1, alors;

s1 = s2;

Ensuite, l'objet ayant "Java" sera éligible pour GC.

  1. Tous les objets créés dans une méthode sont éligibles pour GC une fois la méthode terminée. Par conséquent, une fois que la méthode est détruite de la pile du thread, les objets correspondants dans cette méthode seront détruits.

  2. Island of Isolation est un autre concept où les objets avec des liens internes et aucun lien extrinsèque vers la référence sont éligibles pour la collecte des ordures. "Île d'isolement" de la collecte des ordures

Exemples: Vous trouverez ci-dessous une méthode de classe Camera dans Android. Voyez comment le développeur a pointé mCameraSource sur null une fois qu'il n'est pas requis. Il s'agit d'un code de niveau expert.

public void release() {
        if (mCameraSource != null) {
            mCameraSource.release();
            mCameraSource = null;
        }
    }

Comment fonctionne Garbage Collector?
La récupération de place est effectuée par le thread démon appelé Garbage Collector. Lorsqu'il y a suffisamment de mémoire disponible, ce thread démon a une priorité faible et s'exécute en arrière-plan. Mais lorsque JVM constate que le tas est plein et que JVM veut récupérer de la mémoire, elle augmente la priorité du thread Garbage collector et appelle la méthode Runtime.getRuntime.gc () qui recherche tous les objets qui n'ont pas de référence ou référence nulle et détruit ces objets.

1
Utsav