9
votes

Finalisation gracieusement du référent de softreufence

J'utilise une bibliothèque de recherche qui conseille de conserver l'objet de la poignée de recherche ouverte pour cela peut bénéficier au cache de requête. Au fil du temps, j'ai observé que le cache a tendance à être gonflé (peu de centaines de Megs et à continuer de croître) et l'Ooms a commencé à lancer. Il n'y a aucun moyen d'appliquer des limites de ce cache ni de planifier la quantité de mémoire qu'il peut utiliser. J'ai donc augmenté la limite xmx , mais ce n'est qu'une solution temporaire au problème.

Finalement, je pense à faire cet objet un référent de Java .lang.ref.softreference . Donc, si le système fonctionne bas sur la mémoire libre, cela laisserait l'objet aller et un nouveau pour lequel il serait créé à la demande. Cela diminuerait une certaine vitesse après le départ frais, mais il s'agit d'une bien meilleure alternative que de frapper OOM.

Le seul problème que je vois sur Softreferences est qu'il n'y a pas de moyen propre d'obtenir leurs référents finalisés. Dans mon cas, avant de détruire la poignée de recherche, j'ai besoin de le fermer, sinon le système pourrait être à court de descripteurs de fichiers. Évidemment, je peux envelopper cette poignée dans un autre objet, écrivez un finisseur sur celui-ci (ou accrochez-vous sur une référence / phanterreference) et laisser aller. Mais bon, chaque article de cette planète conseille contre l'utilisation des finaliseurs, et surtout - contre les finaliseurs pour la libération des poignées de fichier (par exemple, Java ED. II, page 27.).

Donc, je suis un peu perplexe. Devrais-je ignorer soigneusement tous ces conseils et continuer. Sinon, y a-t-il d'autres alternatives viables? Merci d'avance.

Edit N ° 1: Le texte ci-dessous a été ajouté après avoir testé du code comme suggéré par Tom Hawtin. Pour moi, il semble que l'une des suggestions ne fonctionne pas ou que vous manquez quelque chose. Voici le code: xxx

si j'exécute le snippet ci-dessus avec -xmx10m et Softreferences (comme dans le code ci-dessus), je reçois des tonnes de est NULL: ( imprimé. Mais si je remplace le code avec myreference (mot notation de deux lignes avec une myreference et commentant des commentaires avec SOFTReference) Je reçois toujours l'OOM.

Comme je l'ai compris à partir des conseils, avoir une référence difficile à l'intérieur MyreFerence ne doit pas empêcher l'objet frapper référence , non?


0 commentaires

4 Réponses :


7
votes

Pour un nombre fini de ressources: Sous-classe Softreference . La référence douce doit indiquer sur l'objet enfermé. Une référence forte dans la sous-classe doit faire référence à la ressource, elle est donc toujours fortement accessible. Lors de la lecture de la référence référence sondage La ressource peut être fermée et supprimée du cache. Le cache doit être libéré correctement (si un Softreference est recueilli, il ne peut pas être affiché sur un référence ).

Soyez prudent que vous n'ayez qu'un nombre fini de ressources inédites dans les anciennes anciennes entrées de cache (en effet, vous pouvez supprimer les références douces avec le cache fini, si cela convient à votre situation). Il est généralement le cas que c'est la ressource non-mémoire plus importante, auquel cas un cache d'expulsion LRU sans objets de référence exotiques ne devrait être suffisant.

(ma réponse n ° 1000. Publié de Londres Diverdad.)


4 commentaires

Je suis surpris que c'était cohérent à distance (c'est-à-dire?) Après une heure ou une heure de sommeil, une journée dans une pièce sombre (avec un service de café pauvre, bien que travaille WiFi) et d'essayer d'écouter un orateur. Mais il fallait être fait.


Tom, pourriez-vous s'il vous plaît poster (ou éditer celui-ci) une réponse plus détaillée, éventuellement accompagnée d'un code (pseudo)? J'ai aussi eu une bonne journée, peut-être demain, je le comprendrai mieux, mais en ce moment, malheureusement, je ne semble pas être capable.


@marcob Je pense qu'une implémentation similaire peut être trouvée ici: JavaSpecialists.eu/archive/issue015.html < / a> Vous voudrez peut-être ajouter des génériques en plus de cela, car cela semble être codé en 2001. Je voulais à l'origine utiliser des valeurs molles avec Google Collections 'MapMaker, mais je n'ai pas pu trouver la possibilité de connecter la logique de finalisation personnalisée. J'ai posté un message à la liste de diffusion de Google-Collections et de voir si elle peut en sortir quelque chose.


Après avoir lu ceci, j'essaie d'éviter ce site: "Lors de l'inspection très minutieuse, j'ai découvert la grande différence entre les fantômes et les faibles références. Les deux sont libérés assez rapidement, mais la référence de fantôme est affectée dans la file d'attente de référence avant son déséquilibre. , ATTENDU QUE la faiblesse référence est enchantée après le désactivation du référent. " Cela prouve un manque clair de compréhension quelles sont ces références et comment elles fonctionnent. Donc, merci, mais non merci.



5
votes

Toms Réponse est la bonne, cependant, le code qui a été ajouté à la question n'est pas le même que celui proposé par Tom. Ce que Tom proposait ressemble plus à ceci:

class Bloat {  // just a heap filler really
    public Reader res;
    private double a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z;

    private final int ii;

    public Bloat(final int ii, Reader res) {
       this.ii = ii;
       this.res = res;
    }
 }

 // as recommended by Tom Hawtin
 class MySoftBloatReference extends SoftReference<Bloat> {
    public final Reader hardRef;

    MySoftBloatReference(Bloat referent, ReferenceQueue<Bloat> q) {
       super(referent, q);
       this.hardRef = referent.res;
    }
 }

 //...meanwhile, somewhere in the neighbouring galaxy...
 {
    ReferenceQueue<Bloat> rq = new ReferenceQueue<Bloat>();
    Set<SoftReference<Bloat>> set = new HashSet<SoftReference<Bloat>>();
    int i=0;

    while(i<50000) {
        set.add(new MySoftBloatReference(new Bloat(i, new StringReader("test")), rq));

        MySoftBloatReference polled = (MySoftBloatReference) rq.poll();

        if (polled != null) {
            // close the reference that we are holding on to
            try {
                polled.hardRef.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        i++;
    }
}


3 commentaires

Serait-il possible de réparer votre code afin qu'il compile? Par exemple. Le constructeur de myreference prend un argument de référents de gonflage et est censé l'affecter au HardRef, mais HARDRFF est d'un type totalement différent (ResourceSetHatmustbecsLost). De plus, pouvez-vous élaborer pourquoi BLOAT est toujours nécessaire une fois que nous avons une ressourceSetHatmustPébecLost? P.s. Je ne serais pas si nécessaire si cette question n'avait aucun point de bonus attaché: P


J'ai mis à jour le code et (espérons-le) a ajouté une explication claire de la façon dont cela fonctionne? Sinon, laissez-moi savoir ...


Le code est corrigé de sorte qu'il compile. Jetez-le simplement dans une classe vide et ajoutez les importations appropriées.



2
votes

AHM.
(Pour autant que je sache), vous ne pouvez pas tenir le bâton des deux extrémités. Soit vous tenez à votre information ou vous le laissez aller.
Cependant ... vous pouvez conserver certaines informations clés qui vous permettraient de finaliser. Bien entendu, les informations essentielles doivent être considérablement plus petites que les "informations réelles" et ne doivent pas avoir les informations réelles dans son graphique d'objet accessible (des références faibles pourraient vous aider là-bas).
Construire sur l'exemple existant (faites attention au champ Informations de clé): XXX

EDIT:
Je veux élaborer sur le "Tenir ton information ou le laisser aller". En supposant que vous ayez eu une façon de tenir votre information. Cela aurait forcé le GC à ne faire valoir que vos données, que les données ne soient réellement nettoyées qu'après que vous avez terminée, dans un deuxième cycle de GC. C'est possible - et c'est exactement ce que finaliser () est pour. Puisque vous avez déclaré que vous ne voulez pas que le deuxième cycle se produise, vous ne pouvez pas contenir vos informations (si A -> B! B ->! A). Ce qui signifie que vous devez le laisser partir.

Edit2:
En fait, un deuxième cycle se produirait - mais pour vos "données clés", pas vos "données de bloat majeur". Les données réelles seraient effacées sur le premier cycle.

Edit3:
De toute évidence, la solution réelle utiliserait un thread séparé pour éliminer de la file d'attente de référence (ne pas sonder (), retirer (), blocage sur le fil dédié).


1 commentaires

J'ai oublié de mentionner - l'exécution de cet exemple avec -xmx 10 Mo ne cédez pas OOM et répertorie toutes sortes de chiffres (supposés des informations clés »).



0
votes

@Paul - Merci beaucoup pour la réponse et la clarification.

@ran - Je pense que dans votre code actuel I ++ manque à la fin de la boucle. De plus, vous n'avez pas besoin de faire rq.remove () dans la boucle que Rq.Poll () supprime déjà la référence en haut, n'est-ce pas?

quelques points:

1) J'ai dû ajouter des instructions de thread.sleep (1) après i ++ dans la boucle (pour les deux solutions de Paul et Ran) pour éviter l'OMM mais qui n'est pas pertinente pour la grande image et que la plate-forme dépend également. Ma machine a un processeur quad-core et exécute Sun Linux 1.6.0_16 JDK.

2) Après avoir examiné ces solutions, je pense que je vais coller à l'aide de finaliseurs. Le livre de Bloch fournit des raisons suivantes:

  • Il n'y a pas de finaliseurs de garantie ne sera exécuté rapidement, donc ne faisant rien de temps critique dans un finaliseur - ni de garanties pour SOFTRERERENCES!
  • ne dépend jamais d'un finaliseur pour mettre à jour l'état persistant critique - je ne suis pas
  • Il y a une pénalité de performance grave pour l'utilisation de finaliseurs - dans mon pire des cas, je finaliserais d'un seul objet par minute environ. Je pense que je peux vivre avec ça.
  • Utilisez Essayez / enfin - oh oui, je vais certainement!

    Avoir une nécessité de créer une énorme quantité d'échafaudeuse juste pour ce qui semble qu'une tâche simple ne me semble pas raisonnable. Je veux dire, littéralement, le taux de WTF par minute serait assez élevé pour quiconque en regardant ce code.

    3) saddly, il n'y a aucun moyen de diviser les points entre Paul, Tom et Ran :( J'espère que Tom ne me dérangerait pas comme il en avait déjà beaucoup d'entre eux :) Juger entre Paul et Ran était beaucoup plus difficile - je pense que les deux réponses au travail et sont correctes. Je ne fixe que le drapeau à la réponse de Paul, car il a été jugé plus élevé (et a une explication plus détaillée), mais la solution de Ran n'est pas mauvaise du tout et serait probablement mon choix si j'avais choisi de le mettre en œuvre à l'aide de Softreferences. Merci gars!


1 commentaires

I ++ - Oui, je ne l'ai probablement pas effectué à travers la copie / la pâte. Pas besoin de supprimer () - correct. Il me manque environ la moitié des références.