2
votes

Comment écrire du code pour aider le garbage collector

Lors de l'entretien, j'ai eu une question - "Comment aider le ramasse-miettes lors de l'écriture de code?".

À mon avis, GC fonctionne vraiment bien et nous n'avons pas besoin d'utiliser autre chose que de bonnes pratiques de base en matière de code, a ajouté plus tard que la fermeture des ressources dans la clause finally aide GC à coup sûr, mais nous avons généralement été surpris par une telle question.

Y a-t-il une bonne réponse? Avons-nous besoin de faire quelque chose d'incroyable pour aider le ramasse-miettes?


3 commentaires

Semble très vague pour une question d'entrevue. Dépend également du ramasse-miettes utilisé.


Quand on empêche le garbage collector de faire son travail? lorsque nous fuyons des objets qui ne sont plus utilisés (avec des classes anonymes ou des références statiques)


C'est une question vraiment étrange. Empêcher le travail de collectionneur ne compte-t-il pas comme une aide? Parce que c'est ce que font la plupart de ces choses.


3 Réponses :


1
votes

Le garbage collector est très efficace et adroit dans son travail mais nous pouvons améliorer sa capacité à collecter les ordures en pointant les variables et les objets sur null, qui ne sont plus utilisés et il n'y a plus de références à eux. Pendant la gestion des fichiers, utilisez les méthodes close () et flush (). Et dans la gestion des threads, détruit le thread lorsqu'il n'est pas utilisé.


4 commentaires

Voulez-vous dire définir par exemple anyVariable = null; lorsque nous ne l'utilisons plus? Je ne pense pas que ce soit une bonne pratique.


@ Michu93 C'est ce que Yash voulait dire. S'il n'y a aucune référence à l'objet, il peut être récupéré. Si vous suivez d'autres bonnes pratiques (petites méthodes, variables locales, etc.), ce n'est pas vraiment nécessaire - si la portée de la variable est aussi petite que possible, ce n'est pas un problème.


Si cela ne fonctionne pas, pour aider gc, nous pourrions limiter la création d'objets par classe singleton.


Cela semble vraiment une question délicate car java est connue pour sa technique de ramassage des ordures



1
votes

Le Garbage Collector est une "tâche" qui scanne périodiquement vos objets pour détecter ce qui n'est pas utilisé (en réalité, c'est un mécanisme pour émuler une machine avec une mémoire infinie).

Pour cette raison, lorsque vous êtes contenant une référence à une instance d'objet dont vous n'avez plus besoin, vous devez la définir sur null afin de faire savoir au Garbage Collector que vous n'êtes plus intéressé par cette instance (et éventuellement ses descendants).

Cela ne signifie pas que vous devez définir chaque variable sur null après utilisation, mais vous devez surveiller les champs. Comme Java n'a pas de modèle de suppression (voir ici pour plus d'informations), vous devez concevoir vos API pour l'imiter: lorsque vous avez fini d'utiliser une instance d'objet contenant une référence que vous souhaitez libérer, vous devez ajouter une méthode appropriée pour effectuer une telle action.

Prenons l'exemple suivant:

XXX

Si une instance de MyClass2 est conservée mais une autre instance accessible de votre programme (par exemple un singleton, ou une instance actuellement dans la pile), vous ne libérerez jamais la mémoire associée à MyClass1 car elle est toujours référencé par m_MyReference.

Est-ce mauvais? Cela dépend de ce que MyClass2 et MyClass1 font vraiment.

Si vous savez que MyClass2 pourrait avoir une très longue durée de vie et que vous souhaitez conserver la référence à MyClass2 mais pour libérer la mémoire associée à MyClass1, vous devez faites quelque chose de similaire au code ci-dessous:

class MyClass2
{
    private MyClass1 m_MyReference;

    public MyClass2()
    {
        m_MyReference = new MyClass1();
    }

    public void DoSomething()
    {
        // do something here that uses m_MyReference.
    }

    public void Dispose()
    {
        m_MyReference = null;
    }

}

De cette façon, vous exposez à l'appelant un moyen de signaler que vous ne détenez plus de référence à des instances dont vous n'avez pas besoin.

N'oubliez pas que le simple fait d'affecter null à une variable ou un champ ne libère pas automatiquement la mémoire. Le garbage collector est asynchrone et s'exécute lorsqu'il le décide. J'espère avoir donné l'idée sans aller trop loin.


3 commentaires

La plupart du temps, vous n'avez pas besoin de références explicitement nulles pour aider le GC , car les durées de vie des objets sont généralement liées. C'est à dire. une instance de MyClass2 dans votre cas devient souvent inaccessible peu de temps après la fin de son cycle de vie (disposer) de toute façon. Il y a des exceptions, bien sur. Mais il est rare que vous continuiez à utiliser un objet et que vous ne définissiez qu'un de ses champs sur null pour aucune autre raison que d'aider le GC. voir stackoverflow.com/q/449409/1362755 pour plus de détails.


Vous avez raison, le niveau et la précision de la réponse sont à la hauteur de la réponse. À mon avis, il suffit de faire la «bonne chose», c'est pourquoi ma réponse allait dans ce sens. Inclure les détails comme l'accessibilité des arbres, les fermetures, etc ... n'aide pas à écrire un bon code, mais vous informe simplement sur des détails non contractuels sur le GC, ce qui, après tout, est une optimisation.


En fait, vous aggravez les choses, car maintenant, l'optimiseur doit reconnaître que votre m_MyReference = null; est obsolète, sinon cette affectation maintient l'instance MyClass2 active plus longtemps que nécessaire. Lorsque vous pensez que quelqu'un conservera une référence à une instance de MyClass2 malgré l'invocation de dispose () , vous devez repenser la conception du logiciel. Lectures recommandées: Java peut-il finaliser un objet lorsqu'il est encore dans la portée? finalize () appelé sur des objets fortement accessibles



1
votes

La question est formulée bizarrement. Le GC n'a pas besoin d'aide dans son travail. Il fonctionnera avec toutes les contraintes qui lui sont imposées ou échouera si les contraintes ne peuvent pas être satisfaites.

Bien sûr, le travail peut être modifié, mais cela ne se fait pas par désir d'alléger le fardeau du GC - ce n'est pas un être humain qui peut s'ennuyer par son travail - mais en raison d'une arrière-pensée, telle que améliorer les performances globales du programme.

Ces éléments sont normalement définis comme des optimisations de latence, de consommation d'énergie, de débit ou d'empreinte mémoire. Mais ce ne sont pas les seules mesures qui intéressent un programmeur. La simplicité et la lisibilité du code sont également importantes.

Le code naïf peut être plus lisible mais moins performant. Si votre objectif est un code facile à lire, effectuer des optimisations complexes qui réduisent la charge du GC pourrait être contre-productif et donc "aider le GC" n'est pas un objectif en soi.

Maintenant, si votre objectif est d'améliorer certaines métriques de performances, certaines optimisations impliquent également l'écriture de code qui réduit le travail effectué par le sous-système de gestion de la mémoire (allocation + GC). Certaines optimisations possibles consistent à éviter les finaliseurs, à trouver des fuites de mémoire, à réduire les allocations inutiles, à éviter les énormes tableaux Object [], à régler les paramètres GC, à acheter un meilleur matériel et à réduire la durée de vie des objets. L'optimisation applicable dépend de l'application et peut être mieux identifiée avec les profileurs, la journalisation GC et autres


0 commentaires