2011-08-30 5 views
3

Le problème est que, d'une certaine façon, en raison de timings de collecte de place, j'ai des compromis dans ma performance. La question peut être généralisée comme:Garbage collection overload, Java

public void loop(BlockingQueue<Runnable> queue) 
    { 
    int j = queue.size(); 
    for(int i =0; i<j;i++)//line2 
    { 
    Runnable runnable = queue.take(); 
    runnable.run();//line4 

    if(Math.random() > 0.9) System.gc();//line5 

    } 

    //line7 //will 'runnable = null;' answer the question, logically it looks right 

    } 

maintenant normalement la file d'attente passé comme argument contiendra plus de 40.000 éléments normalement. Et parce que je suis en train d'itérer sur la file d'attente dans une boucle, même si les objets 'run' sont hors de portée, ils ne sont toujours pas disponibles pour garbage Collection car ils sont dans invisible state. Par conséquent, si je n'ai pas la ligne 5, alors il y aura une énorme charge sur le garbage collector quand la méthode sortira de la pile. Imaginez si plusieurs threads accèdent simultanément au menthod.

Mes questions:

  1. est la ligne 5 nécessaire? Y a-t-il un autre substitut?
  2. Si je dois avoir la ligne 5, j'ai découvert que la performance était très très mauvaise par rapport à ne pas l'avoir.

En fin de compte garbage collection doit se produire? Je suis incapable de comprendre quand cela devrait arriver.

PS: Javascript est désactivé sur mon ordinateur, donc je ne peux pas commenter les réponses. Je vais éditer le poste ici pour les commentaires:

@amit: J'ai changé le code, je pense que vous avez compris l'essence du problème. Le code est juste un échantillon.

@Tobi: Merci, mais comment va configurer une plus grande taille de tas, résoudre le problème. C'est seulement retarder l'heure de gc. Donc, vous pensez qu'il fonctionnera le mieux sans gc manuel? En outre de http://java.sun.com/docs/books/performance/1st_edition/html/JPAppGC.fm.html, il dit que seulement une fois la méthode est prise de la pile, alors seulement dans ce cas, il serait disponible pour la récupération de place. Et j'ai essayé avec finalize() (en ayant une impression, pas la bonne façon, mais devrait au moins travailler une fois pour 100000 objets), il n'y a absolument pas de gc.

@Paolo: Merci. Ce que j'essaye d'implémenter est un modèle de pipelining, où chaque thread a une file d'attente de meassage, fondamentalement un cadre où n'importe quel fil peut signaler un runnable à l'autre thread (si cela a du travail avec le thread), et l'autre thread exécutera Quand je veux dire, surcharger quand la méthode sort de la pile, ce que je veux dire, c'est que la coltination des ordures finira par arriver, si cela arrive plus tard, alors effacer 40 000 éléments prendra beaucoup de temps.

@ Joachim Sauer: System.gc peut collecter des objets invisibles, c'est juste que le garbage collector ne les collecte pas automatiquement. Mais lorsqu'il est forcé, il fait comme pour: http://java.sun.com/docs/books/performance/1st_edition/html/JPAppGC.fm.html

+0

J'ai changé: line3: run-> runnable, wueue-> queue, rollback si je me trompe, et vous voulez dire en fait les membres de la classe, mais je suppose non – amit

+1

aussi: Je doute que vous vouliez itérer de 'i = 0' à 'queue.size()', note 'queue.size()' change quand vous utilisez 'take()', donc si vous avez 2 éléments dans la file, vous ne 'irez' que sur le premier, car après 'take()' change la taille de 1, et 'i <1 == false'. probablement vous cherchez while (queue.isEmpty() == false) ' – amit

+2

Vous avez dit que vous avez généralisé le problème: pouvez-vous * reproduire * le problème avec ** ce ** code généralisé? Si ce n'est pas le cas, vous pourriez très bien avoir trop généralisé et devrez peut-être nous montrer le vrai code. –

Répondre

2

Laissez le garbage collector faire son travail, et si nécessaire (et alors seulement), réglez le garbage collector en utilisant des arguments VM, mais ne pas mettre un appel à System.gc() dans une boucle intérieure comme ce.Il est quasiment garanti qu'un tel appel détruira les performances, car il force un cycle complet de collecte des ordures, alors que normalement le garbage collector 1) ne les collecte que lorsque le tas est presque plein (donc vous pouvez réduire/augmenter le nombre des collections en donnant à la VM un tas plus grand/plus petit), et 2) ne recueille que les objets les plus jeunes la plupart du temps (ie, generational garbage collection).

En ce qui concerne votre cas particulier, état invisible signifie que l'objet référencé par la runnable variable peut encore être fortement référencé à la ligne 7, même si la variable locale runnable est hors de portée à ce moment-là. Cependant, vm ne réserve qu'un slot pour la variable runnable, qui est réutilisée dans chaque itération de votre boucle. Dès que vous prenez l'élément suivant dans la file d'attente et que vous le stockez dans runnable, il écrase la référence à l'élément précédent, rendant ainsi cet élément précédent éligible pour la récupération de place. En d'autres termes, un seul élément sera probablement dans cet état invisible (par appel à loop).

+0

Notez qu'une taille de segment de mémoire maximale (et initiale) * beaucoup * supérieure à celle dont l'application a réellement besoin * peut avoir un impact négatif sur les performances en réduisant la localité (les éléments avec lesquels vous devez travailler en même temps sont répartis dans de nombreuses zones de mémoire différentes, ce qui réduit efficacement l'efficacité des caches mémoire du processeur). Trop de mémoire de tas peut également rendre le travail du GC plus difficile. –

+0

Bon point, reformulé un peu plus neutre. – Tobi

+0

Juste pour plus de clarté - 'System.gc()' ne force pas un cycle complet de récupération de place, c'est simplement un indice à la machine virtuelle que l'on devrait faire. Le reste est vrai cependant, on est souvent * effectué * lorsque cette méthode est appelée ce qui tuerait la performance. – berry120

2

Fondamentalement vous n'êtes pas supposé pour savoir quand collecter les déchets, c'est-à-dire jusqu'à la JVM. La ligne 5 n'est pas nécessaire et, comme vous l'avez remarqué, sera préjudiciable à la performance de votre application.

Si vous tentez de forcer plusieurs fois le CPG, cela signifie que vous avez un problème avec la conception de votre programme.

soudainement il y aura une énorme charge sur le garbage collector lorsque la méthode sort de la pile.

Pas nécessairement, le GC ne s'exécute pas chaque fois que des objets sortent de la portée ou qu'une image de pile est sautée. La JVM détermine quand effectuer une exécution GC et cela peut être immédiatement, il se peut que ce soit dans le futur.

Qu'essayez-vous de réaliser avec cette méthode? Il semble que vous ayez une collection de tâches que vous voulez exécuter en parallèle? Si tel est le cas, vous devriez regarder le ExecutorService pour mettre des tâches sur un pool de threads pour vous.

3

1) La ligne 5 est-elle nécessaire? Y a-t-il un autre substitut?

L'appel à System.gc() est inutile. En fait, il est positivement nocif pour le débit d'appeler System.gc(). Il suffit de supprimer la ligne 5. Il n'est pas nécessaire de la remplacer par quoi que ce soit.

2) Si je dois avoir la ligne 5, j'ai découvert que la performance était très très mauvaise par rapport à ne pas l'avoir.

Ceci est entièrement conforme à mes attentes. Voir au dessus.

Et parce que je suis itérer sur la file d'attente dans une boucle, même si les objets déjà « run » sont hors de portée, ils ne sont pas encore disponibles pour les ordures Collection parce qu'ils sont dans un état invisible

en fait:

  • il peut être au plus un objet dans l'état « invisible » référencé par un hors-portée des variables runnable et

  • forçant la collecte des ordures ne le récupèrera pas de toute façon.

System.gc peut collecter des objets invisibles.

Cette affirmation est fausse. En fait, le problème des objets invisibles est que le GC ne peut pas les collecter. En effet, l'article que vous lié à dit très clairement:

"Parce que les objets invisibles ne peuvent être collectées, c'est une cause possible de fuites de mémoire Si vous rencontrez cette situation, vous pourriez avoir. pour annuler explicitement vos références pour activer la récupération de place. "

(Je souligne.)


Franchement, je pense que vous essayez de résoudre un problème qui ne existe pas. Ou s'il existe, cela n'a rien à voir avec des objets invisibles.

Et s'il y a vraiment un problème avec les objets invisibles, alors la solution est simplement d'assigner null à la variable à la fin de la boucle.

+0

bonne explication :-) – luketorjussen