web-dev-qa-db-fra.com

Java garbage collector - Quand est-il collecté?

Qu'est-ce qui détermine quand le ramasse-miettes collecte réellement? Cela se produit-il après un certain temps ou une certaine quantité de mémoire épuisée? Ou y a-t-il d'autres facteurs?

46
nalo

Il s'exécute lorsqu'il détermine qu'il est temps d'exécuter. Une stratégie courante dans les récupérateurs de place générationnels consiste à exécuter le collecteur lorsqu'une allocation de mémoire de génération 0 échoue. Autrement dit, chaque fois que vous allouez un petit bloc de mémoire (les gros blocs sont généralement placés directement dans les générations "plus anciennes"), le système vérifie s'il y a suffisamment d'espace libre dans le segment gen-0, et s'il n'y en a pas, il s'exécute le GC pour libérer de l'espace pour que l'allocation réussisse. Les anciennes données sont ensuite déplacées vers le segment de mémoire gen-1, et lorsque l'espace est insuffisant, le GC exécute une collecte sur celui-ci, mettant à niveau les données qui ont été les plus anciennes vers le segment gen-2, etc. Ainsi, le GC ne se contente pas de "courir". Il peut fonctionner uniquement sur le tas gen et la plupart des collections le feront), ou il peut vérifier à chaque génération s'il doit vraiment libérer beaucoup de mémoire (ce qui n'est nécessaire que rarement).

Mais c'est loin de la stratégie seulement. Un GC simultané s'exécute en arrière-plan, nettoyant pendant l'exécution du programme. Certains GC peuvent s'exécuter dans le cadre de chaque allocation de mémoire. Un collecteur incrémentiel peut le faire, en analysant quelques objets à chaque allocation de mémoire.

Le point entier dans un garbage collector est qu'il devrait simplement faire sa chose sans nécessiter aucune entrée de l'utilisateur. Donc, en général, vous ne pouvez pas, et ne devriez pas, prédire quand cela se déroulera.

Je crois que Suns JVM a gagné un GC générationnel il n'y a pas si longtemps (v1.6 peut-être? Je n'ai pas codé Java depuis des lustres, donc je n'en suis pas sûr, mais je me souviens avoir été surpris il n'y a pas si longtemps l'un des arguments de vente de la nouvelle version était "un GC générationnel", notamment parce que .NET en a un depuis le premier jour.)

Les autres JVM sont bien sûr libres de choisir la stratégie qui leur convient.

EDIT: La partie ci-dessus concernant Java et le GC générationnel n'est pas vraie. Voir ci-dessous pour plus de détails:

Les machines virtuelles 1.0 et 1.1 utilisaient un collecteur de balayage de marque, qui pouvait fragmenter le tas après un garbage collection. À partir de Java 1.2, les machines virtuelles sont passées à un collecteur générationnel, qui a un bien meilleur comportement de défragmentation (voir --- (Théorie et pratique Java: collecte et performances des ordures ).

Donc Java a en fait un GC générationnel pour les âges. Quoi de neuf dans Java 6 est le garbage collector (G1) qui est disponible dans Java 6u14. Selon l'article revendiquant la sortie de 1.6.0_14 : Il n'est pas activé par défaut. Le collecteur parallèle est toujours le GC par défaut et le GC le plus efficace pour une utilisation domestique courante. G1 est censé être une alternative pour le collecteur simultané. Il est conçu pour être plus prévisible et permettre une allocation rapide avec la conception des régions de mémoire.

28
jalf
  • Cela dépend de la façon dont le programme JIT est compilé.
  • De l'extérieur, nous ne pouvons pas vraiment dire quand il se déroulera.
  • Il suit un algorithme qui dépend de ce GC particulier.
  • La machine virtuelle Java s'exécute sur la machine cliente avec une mémoire virtuelle en cas de Windows par défaut est de 4 Go. Cela dépend également de cette mémoire virtuelle libre à ce moment particulier.

Vous pouvez essayer ce petit programme pour vérifier le comportement du GC

public class GCTest {

   final int NELEMS = 50000;

   void eatMemory() {

      int[] intArray = new int[NELEMS];

      for (int i=0; i<NELEMS; i++) {
        intArray[i] = i;
      }

   }

   public static void main (String[] args) {

      GCTest gct = new GCTest();

      // Step 1: get a Runtime object
      Runtime r = Runtime.getRuntime();

      // Step 2: determine the current amount of free memory
      long freeMem = r.freeMemory();
      System.out.println("free memory before creating array: " + freeMem);

      // Step 3: consume some memory
      gct.eatMemory();

      // Step 4: determine amount of memory left after consumption
      freeMem = r.freeMemory();
      System.out.println("free memory after creating array:  " + freeMem);

      // Step 5: run the garbage collector, then check freeMemory
      r.gc();
      freeMem = r.freeMemory();
      System.out.println("free memory after running gc():    " + freeMem);
   }
}

sortie possible - peut être différent dans votre cas

free memory before creating array: 4054912
free memory after creating array:  3852496
free memory after running gc():    4064184

Vérifiez ce lien http://www.devdaily.com/Java/edu/pj/pj010008/

7
Xinus

Cela dépend beaucoup du garbage collector que vous utilisez réellement, de la manière dont il est réglé et de beaucoup d'entrées.

Pour une analyse du garbage collector HotSpot (le plus commun qui vient avec Java) et comment il est réglé, vous pouvez consulter ce lien

5
tschaible

Lorsque JVM n'a pas d'espace mémoire nécessaire pour s'exécuter, le garbage collector s'exécute et supprime les objets inutiles et alloue de la mémoire pour JVM.

Les objets inutiles sont les objets qui n'ont aucune référence (adresse) pour cela.

Il y a principalement 4 points pour les objets éligibles au ramasse-miettes.

  1. Référencement nul

    Le garbage collector peut supprimer un objet lorsque la variable de référence de l'objet est affectée null comme valeur

        A a = new A();
        a = null;
    
  2. Réaffectation

    Lorsqu'un autre objet est affecté à la variable de référence d'un objet, l'ancien objet référencé peut être supprimé par le garbage collector.

      A a = new A(100);
      a =new A(200);
    
  3. Portée locale

    Si un objet est créé à l'intérieur d'un bloc, cet objet est éligible pour le ramasse-miettes à l'extérieur de ce bloc.

      if(condition){
    
         A a = new A();
    
      }
    
  4. Isolement

    Un objet peut référencer un autre objet mais il doit y avoir au moins une variable de référence (adresse) pour ces objets dans la pile, sinon tous ces objets sont éligibles pour le garbage collector.

          class A{
                A r;
                A(int i){
                 //something   
               }
          } 
    
          A a1 = new A(100);
          a1.r = new A(101);
          a1.r.r = new A(102);
          a1.r.r.r = a1;
    
          a1  = null //all ojects are eligible to garbage collector  
    
2
Nisal Edu

Cela dépend complètement de la JVM réelle et de ce qu'elle choisit de faire, et est fondamentalement hors de vos mains en tant que programmeur. Des experts inconditionnels à la barbe grise mai veulent dire à la JVM qu'ils connaissent mieux, mais pour les simples mortels, cela devrait être considéré comme de la magie noire mieux laissé seul.

Ce qui devrait vous préoccuper, c'est s'il peut suivre le rythme que vos programmes créent et rejettent les objets. Sinon, votre programme entier est arrêté pendant le nettoyage global. Cela se traduit par de très mauvais temps de réponse, mais cela arrive rarement pour les machines virtuelles Java modernes sur les ordinateurs modernes.

Si vous êtes curieux de savoir ce qui se passe dans votre programme et quand, alors étudiez l'outil "jvisualvm" dans les versions récentes du JDK Java 6. Il est vraiment idéal pour jeter un œil à l'intérieur.

Le garbage collector s'exécute lorsqu'il a besoin de ressources et sur une base régulière que vous pouvez influencer en disant quand est le bon moment pour consacrer du CPU à la collecte, en utilisant System.gc ()

Vous pouvez aider le garbage collector en annulant explicitement les références, par exemple en donnant à vos objets init() des méthodes qui allouent des ressources et cleanup() des méthodes qui nettoient explicitement ces ressources et en annulant leurs références. En annulant vous-même les références, vous évitez que le ramasse-miettes ne doive trouver des grappes d'objets ayant plus de chemins vers une racine.

1
rsp