web-dev-qa-db-fra.com

Comment forcer la récupération de place en Java?

Est-il possible de forcer la récupération de place en Java, même s’il est délicat à faire? Je connais System.gc(); et Runtime.gc(); mais ils suggèrent seulement de faire du GC. Comment puis-je forcer le GC?

192
user179172

Votre meilleure option est d'appeler System.gc() , ce qui indique simplement au récupérateur de place que vous souhaitez qu'il effectue une collecte. Il n’existe aucun moyen de force et de collecte immédiate, car le ramasse-miettes est non déterministe.

149
Andrew Hare

La bibliothèque jlibs a une bonne classe d’utilitaires pour la récupération de place . Vous pouvez forcer la récupération de place en utilisant un petit truc astucieux avec WeakReference objects.

RuntimeUtil.gc () à partir de jlibs:

   /**
    * This method guarantees that garbage collection is
    * done unlike <code>{@link System#gc()}</code>
    */
   public static void gc() {
     Object obj = new Object();
     WeakReference ref = new WeakReference<Object>(obj);
     obj = null;
     while(ref.get() != null) {
       System.gc();
     }
   }
50
shams

Le meilleur (sinon le seul) moyen de forcer un CPG serait d’écrire une machine virtuelle Java personnalisée. Je crois que les garbage collectors sont enfichables, vous pouvez donc probablement choisir l'une des implémentations disponibles et la modifier.

Remarque: Ce n'est pas une réponse facile.

40
Mainguy

Utilisation de l’interface machine virtuelle (JVM TI) Java ™ , la fonction

jvmtiError ForceGarbageCollection(jvmtiEnv* env)

va "Forcer le VM à effectuer une récupération de place." La TI JVM fait partie de l’architecture de débogage de la plateforme Java ™ (JPDA) .

38
trashgod

OUIil est presque possible de forcer vous devez appeler des méthodes dans le même ordre et en même temps, celles-ci sont:

System.gc ();
System.runFinalization ();

même s'il ne s'agit que d'un seul objet pour nettoyer l'utilisation de ces deux méthodes en même temps, forcer le ramasse-miettes à utiliser la méthode finalise() d'objet inaccessible, libérant ainsi la mémoire affectée et procédant de la même manière que la méthode finalize().

CEPENDANTc'est une pratique horrible d'utiliser le ramasse-miettes car son utilisation pourrait entraîner une surcharge du logiciel qui pourrait être encore pire que sur la mémoire, le ramasse-miettes a son propre thread qui n'est pas possible de contrôler plus en fonction de l'algorithme utilisé par le gc pourrait prendre plus de temps et est considéré comme très inefficace, vous devriez vérifier votre logiciel si le problème se pose avec l'aide du gc car il est définitivement cassé, une bonne solution ne doit pas dépendre du gc.

NOTE: juste pour garder à l'esprit que cela ne fonctionnera que si, dans la méthode de finalisation, il ne s'agit pas d'une réaffectation de l'objet, si cela se produit l'objet restera en vie et qu'il aura une résurrection techniquement possible.

24
legramira

Dans la documentation de OutOfMemoryError , il est indiqué qu'il ne sera pas lancé, sauf si VM n'a pas réussi à récupérer de la mémoire après un nettoyage complet. Donc, si vous continuez à allouer de la mémoire jusqu'à ce que vous obteniez l'erreur, vous aurez déjà forcé une récupération de place complète. 

Vraisemblablement, la question que vous vouliez vraiment poser était: "Comment puis-je récupérer la mémoire que je pense que je devrais récupérer par la récupération de place?"

18
Pete Kirkham

Pour demander manuellement le GC (pas à partir de System.gc ()): 

  1. Allez à: dossier bin dans JDK, par exemple,-C:\Program Files\Java\jdk1.6.0_31\bin
  2. Ouvrez jconsole.exe
  3. Connectez-vous au processus local souhaité.
  4. Allez à la mémoire et cliquez sur Perform GC.
15
Pinkesh Sharma

.gc est candidat à l’élimination dans les prochaines versions - un ingénieur Sun a déjà déclaré que moins de vingt personnes dans le monde savent comment utiliser .gc (). structure de données utilisant les données générées par SecureRandom, au-delà de 40 000 objets, la machine virtuelle ralentirait comme si elle n'avait plus de pointeurs. Clairement, il s’étouffait sur les tables de pointeurs 16 bits et présentait le comportement classique des "machines défaillantes".

J'ai essayé -Xms et ainsi de suite, j'ai continué à tourner jusqu'à ce qu'il atteigne environ 57, xxx. Ensuite, il passerait de 57,127 à 57,128 après un gc () - à peu près à la vitesse de gonflement du code au camp Easy Money.

Votre conception nécessite un remaniement fondamental, probablement une approche de fenêtre coulissante. 

11
Nicholas Jordan

Vous pouvez déclencher un GC à partir de la ligne de commande. Ceci est utile pour batch/crontab:

jdk1.7.0/bin/jcmd <pid> GC.run

Voir:

8
guest

La spécification JVM ne dit rien de spécifique sur la récupération de place. De ce fait, les fournisseurs sont libres d’implémenter GC de leur propre manière.

Donc, cette imprécision provoque une incertitude dans le comportement de la collecte des ordures. Vous devez vérifier les détails de votre machine virtuelle Java pour en savoir plus sur les approches/algorithmes de récupération de place. Il existe également des options pour personnaliser le comportement.

6
rai.skumar

Si vous devez forcer la récupération de place, vous devriez peut-être réfléchir à la façon dont vous gérez les ressources. Créez-vous des objets volumineux qui persistent dans la mémoire? Créez-vous des objets volumineux (par exemple, des classes graphiques) dotés d'une interface Disposable et n'appelant pas dispose() lorsque vous avez terminé? Déclarez-vous quelque chose au niveau de la classe dont vous n'avez besoin que dans une seule méthode?

4
Bob Kaufman

Il serait préférable que vous décriviez la raison pour laquelle vous avez besoin d'un ramassage des ordures. Si vous utilisez SWT, vous pouvez disposer de ressources telles que Image et Font pour libérer de la mémoire. Par exemple:

Image img = new Image(Display.getDefault(), 16, 16);
img.dispose();

Il existe également des outils pour déterminer les ressources non réparties.

2
Paul Lammertsma

Utilisez Runtime.getRuntime().gc() ou utilisez la méthode utilitaire System.gc()

1
nabster

Si vous manquez de mémoire et obtenez une OutOfMemoryException, vous pouvez essayer d'augmenter la quantité d'espace de mémoire disponible pour Java en démarrant votre programme avec Java -Xms128m -Xmx512m au lieu de Java. Cela vous donnera une taille de tas initiale de 128 Mo et un maximum de 512 Mo, ce qui est beaucoup plus que la norme 32 Mo/128 Mo.

0
Viktor Dahl

Si vous utilisez JUnit et Spring, essayez d’ajouter ceci à chaque classe de test:

@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
0
Aliuk

Une autre option est de ne pas créer de nouveaux objets.

La mise en commun des objets est absente pour réduire le besoin de GC en Java.

Le regroupement d'objets ne sera généralement pas plus rapide que la création d'objets (en particulier pour les objets légers), mais il est plus rapide que la récupération de place. Si vous avez créé 10 000 objets et que chaque objet contient 16 octets. Cela représente 160 000 octets que GC doit récupérer. D'un autre côté, si vous n'avez pas besoin de tous les 10 000 en même temps, vous pouvez créer un pool pour recycler/réutiliser les objets, ce qui élimine la nécessité de construire de nouveaux objets et élimine le besoin de gérer de vieux objets.

Quelque chose comme ceci (non testé) . Et si vous voulez qu'il soit thread-safe, vous pouvez échanger la liste LinkedList contre une ConcurrentLinkedQueue.

public abstract class Pool<T> {
    private int mApproximateSize;
    private LinkedList<T> mPool = new LinkedList<>();

    public Pool(int approximateSize) {
        mApproximateSize = approximateSize;
    }

    public T attain() {
        T item = mPool.poll();
        if (item == null) {
            item = newInstance();
        }
        return item;
    }

    public void release(T item) {
        int approxSize = mPool.size(); // not guaranteed accurate
        if (approxSize < mApproximateSize) {
            recycle(item);
            mPool.add(item);
        } else if (approxSize > mApproximateSize) {
            decommission(mPool.poll());
        }
    }

    public abstract T newInstance();

    public abstract void recycle(T item);

    public void decommission(T item) { }

}
0
Aaron T Harris

(Désolé, je ne peux pas ajouter ceci en tant que commentaire car je n'ai pas assez de points de réputation.)

Une fois, j'ai interviewé une entreprise de traitement d'images pour un travail en Java (même si je n'avais aucune expérience en Java.)

Leur histoire de malheur qui m'intéressait, était que leur programme alloue un énorme tampon pour l'image. Une fois, ils avaient fini avec l'image et la mémoire, ils la déféraient. Sachant qu'ils devaient vraiment récupérer la mémoire plus tôt que tard, ils ont essayé d'utiliser un appel explicite à Java gc () au cours d'une période d'inactivité du programme. Malheureusement, gc () est simplement une suggestion pour l'exécution Java et n'a eu aucun effet.

Si je me souviens bien, ils ont fini par devoir recycler eux-mêmes la mémoire.

0
Clem Wang

Sur OracleJDK 10 avec G1 GC, un seul appel à System.gc() fera en sorte que GC nettoie l’ancienne collection. Je ne suis pas sûr si GC fonctionne immédiatement. Cependant, GC ne nettoiera pas la collection Young, même si System.gc() est appelé plusieurs fois dans une boucle. Pour que GC nettoie la collection Young, vous devez allouer une boucle (par exemple, new byte[1024]) sans appeler System.gc(). Appeler System.gc() pour une raison quelconque empêche GC de nettoyer la collection Young.

0
Nathan

Vraiment, je ne te comprends pas. Mais être clair sur "Création d'objets infinis" Je voulais dire qu'il y a un morceau de code à mon grand système faire la création de objets qui manipule et vivant dans mémoire, je ne pouvais pas obtenir ce morceau de code en fait, juste geste !!

C'est correct, seul geste. Vous avez à peu près les réponses standard déjà données par plusieurs affiches. Prenons ceci un par un:

  1. Je ne pouvais pas obtenir ce morceau de code.

Bien, il n’existe pas de jvm réel - c’est seulement une spécification, un tas d’informatique décrivant un comportement souhaité ... Je me suis récemment lancé dans l’initialisation d’objets Java à partir de code natif. Pour obtenir ce que vous voulez, le seul moyen est de faire ce que l’on appelle la suppression agressive. Les erreurs, si elles sont mal faites, sont si graves que nous devons nous limiter à la portée initiale de la question: 

  1. un morceau de code sur mon gros systèmedo création d'objets

La plupart des affiches ici supposeront que vous dites que vous travaillez sur une interface, si nous devions voir si l'objet entier ou un élément à la fois vous était remis.

Si vous n'avez plus besoin d'un objet, vous pouvez affecter la valeur null à l'objet, mais si vous vous trompez, une exception de pointeur null est générée. Je parie que vous pouvez obtenir de meilleurs résultats si vous utilisez NIO

Chaque fois que vous ou moi-même ou quelqu'un d’autre obtenons: " S'il vous plaît, j’en ai terriblement besoin. " C’est un précurseur presque universel de la destruction presque totale de ce que vous essayez de travailler .... écrivez-nous un petit exemple de code, en désinfectant tout code réellement utilisé et montrez-nous votre question.

Ne soyez pas frustré. Cela résout souvent votre dba en utilisant un paquet acheté quelque part et la conception originale n’a pas été modifiée pour les structures de données volumineuses. 

C'est très commun.

0
Nicholas Jordan