2009-08-09 5 views
44

Quelqu'un a-t-il recherché les coûts d'exécution impliqués dans la création et la collecte des ordures Java WeakReference? Y a-t-il des problèmes de performances (par exemple, la contention) pour les applications multithreads?Coût de l'utilisation de références faibles en Java

EDIT: Il est évident que les réponses réelles dépendront de la JVM, mais les observations générales sont également les bienvenues.

EDIT 2: Si quelqu'un a fait un benchmarking de la performance, ou peut pointer vers des résultats d'étalonnage, ce serait idéal. (Désolé, mais la prime a expiré ...)

+0

Évidemment, cela dépendra de la mise en œuvre du JDK, Sun vs IBM vs JRockit, etc. –

+4

Début d'une réponse dans un article de [Goetz] (http://www.ibm.com/developerworks/java/library/j- jtp01246/index.html): * A chaque garbage collection, une liste d'objets de référence doit être construite, et chaque référence doit être traitée de manière appropriée, ce qui ajoute du temps de référence par référence à chaque collection, que le référent soit collecté ou non. ce temps. Les objets de référence eux-mêmes sont sujets à la collecte des ordures et peuvent être collectés avant le référent, auquel cas ils ne sont pas mis en file d'attente. * – assylias

Répondre

12

Les WeakReferences ont un impact négatif sur le garbage collector de CMS. Autant que je peux voir du comportement de notre serveur il influence le temps de phase de remarque parallèle. Pendant cette phase, tous les threads de l'application sont arrêtés, ce qui est extrêmement indésirable. Donc, vous devez faire attention avec WeakReferences.

+0

Désolé pour cela, mais j'essaie de comprendre les raisons d'un tel comportement sur les forums Sun maintenant :) – Vitaly

+2

Vitaly, en as-tu plus maintenant? Si vous avez trouvé des informations sur les forums Sun, pouvez-vous poster un lien? Merci! – Owen

+0

Quel genre d'impact ont-ils, évidemment il y a un coût, car gc a besoin de cas particuliers faibles références etc –

3

La mise en cache à l'aide de références faibles peut ralentir considérablement votre application si elle est reconstruite à la demande, par ex. dans getters:

public Object getSomethingExpensiveToFind() { 
    if(cache.contains(EXPENSIVE_OBJ_KEY)) { 
     return cache.get(EXPENSIVE_OBJ_KEY); 
    } 

    Object sth = obtainSomethingExpensiveToFind(); // computationally expensive 
    cache.put(EXPENSIVE_OBJ_KEY, sth); 
    return sth; 
} 

imaginer ce scénario:

1) application est faible sur la mémoire

2) GC nettoie les références faibles, ce cache est effacé trop

3) application continue , beaucoup de méthodes comme getSomethingExpensiveToFind() sont invoquées et reconstruire le cache

4) l'application est à nouveau faible en mémoire

5) GC nettoie l'usure des références, efface le cache

6) l'application continue, beaucoup de méthodes comme getSomethingExpensiveToFind() sont invoquées et reconstruire le cache à nouveau

7) et ainsi de suite ...

Je suis tombé sur un tel problème - l'application a été interrompue par GC très souvent et il a complètement détruit tout le point de mise en cache. En d'autres termes, si elles sont mal gérées, les références faibles peuvent ralentir votre application.

+1

Cela ne répond pas à la question que j'ai posée. Vous êtes en train de dire que l'utilisation imprudente de références faibles peut être mauvaise pour les performances ... en raison du débordement du cache d'objets. Mais la question concerne les frais généraux des références faibles elles-mêmes. (Idéalement, je voudrais une réponse qui donne des mesures réelles pour ces frais généraux, mais je me contenterais aussi d'une explication * autoritaire * de la façon dont ils sont encourus.) –

+0

alors vous auriez dû poser des questions sur * metrics * et * benchmarks * spécifiquement – mantrid

+0

J'ai fait. Dans l'avis de prime. Avez-vous lu ça? Mais de toute façon, votre réponse n'est clairement pas pertinente à la question telle que posée. –

4

J'ai implémenté un garbage collector Java une fois, donc tout ce que j'ai pu accomplir est une limite inférieure (faible) sur ce qui est possible.

Dans mon implémentation, il y a une petite quantité constante de surcharge supplémentaire pour chaque référence faible lorsqu'elle est visitée pendant la récupération de place. Donc, le résultat est le suivant: je ne m'inquiéterais pas, ce n'est pas un gros problème à moins d'utiliser des zillions de références faibles. Plus important encore, le coût est proportionnel au nombre de références faibles existantes, et non à la taille du tas global. Cependant, cela ne veut pas dire qu'un garbage collector prenant en charge les références faibles sera aussi rapide que celui qui ne le fait pas. La question supposée ici est, étant donné que Java supporte les références faibles, quel est le coût supplémentaire de leur utilisation?

Mine était un simple "stop the world" marque/balayage garbage collector.Lors de la récupération de place, elle détermine pour chaque objet si cet objet est actif ou non et définit un bit LIVE dans l'en-tête de l'objet. Ensuite, il passe à travers et libère tous les objets non vivants.

Pour gérer les références faibles que vous ajoutez simplement les éléments suivants:

  • Ignorer les références faibles lors de la configuration LIVE bits (à savoir, ils ne causent pas le bit LIVE sur l'objet référencé à définir).
  • Pendant l'étape de balayage, ajoutez une vérification spéciale comme suit: si l'objet que vous visitez est LIVE, et qu'il s'agit d'un WeakReference, cochez l'objet auquel il fait référence, et si cet objet n'est pas LIVE, effacez la référence .

De petites variations de cette logique fonctionnent pour les références logicielles et fantômes.

La mise en œuvre est here si vous êtes vraiment curieux.

+0

C'est très intéressant. (Je pense que l'implémentation de HotSpot est différente.) Comment gérez-vous le cas où une méthode finalize reloue l'objet référencé? Cela n'aurait-il pas besoin de déclencher une re-marque (partielle)? –

+0

Je suis sûr à 100% que l'implémentation de HotSpot est non seulement différente mais beaucoup plus sophistiquée :) Re: finaliser, ce n'est qu'une étape supplémentaire pour les objets non-LIVE. Au lieu de "ça passe et libère tous les objets non-live" il devrait vraiment dire "il passe à travers et met en file d'attente pour la finalisation de tous les objets non vivants". – Archie

+0

Re: finalisation, vous devez définir un bit dans l'en-tête de l'objet qui indique si 'finalize()' a été invoqué ou non, donc vous ne le faites pas deux fois comme requis. Donc, en réalité, les objets qui ne sont pas «LIGHT» sont mis en file d'attente pour être finalisés si le bit n'est pas défini, ou libérés immédiatement si le bit est positionné. – Archie

Questions connexes