Aidez-moi à régler un différend avec un collègue: la définition d'une variable ou d'une collection sur null dans Java facilite-t-elle la récupération de place et réduit-elle l'utilisation de la mémoire? Si j'ai un programme long et que chaque fonction peut être appelée de manière itérative (potentiellement des milliers de fois): Définir toutes les variables qu'il contient sur null avant de renvoyer une valeur à la fonction parent aide-t-il à réduire la taille de mémoire/l'utilisation de la mémoire?
C'est la vieille tradition de performance. C'était vrai en 1.0 jours, mais le compilateur et la JVM ont été améliorés pour éliminer le besoin (si jamais il en existait). Cet excellent article d'IBM entre dans les détails si vous êtes intéressé: Théorie et pratique de Java: Collecte de place et performances
De l'article:
Il existe un cas où l'utilisation de l'annulation explicite est non seulement utile, mais pratiquement requise, et c'est dans ce cas qu'une référence à un objet est portée plus largement qu'elle n'est utilisée ou considérée comme valide par la spécification du programme. Cela inclut des cas tels que l’utilisation d’un champ statique ou d’instance pour stocker une référence à un tampon temporaire, plutôt qu’une variable locale, ou l’utilisation d’un tableau pour stocker les références pouvant rester accessibles par l’exécution mais pas par la sémantique implicite du programme.
Traduction: "explicitement null" objets persistants qui ne sont plus nécessaires. (Si vous voulez. "Requis virtuellement", une déclaration trop forte?)
Java VM Spec
12.6.1 Mise en œuvre de la finalisation Chaque objet peut être caractérisé par deux attributs: il peut être accessible, finalisable, ou inaccessible, et il peut également être non finalisé, finalisable ou finalisé.
Un objet accessible est tout objet accessible dans n'importe quel calcul continu potentiel à partir de n'importe quel thread en direct . Il est possible de concevoir des transformations optimales d’un programme qui réduisent le nombre d’objets accessibles à un nombre inférieur à celui des objets pouvant être considérés naïvement comme tels. Par exemple, un compilateur ou un générateur de code peut choisir de définir une variable ou un paramètre qui ne servira plus à null pour que le stockage d'un tel objet soit potentiellement récupérable plus tôt.
Discussion
Un autre exemple de cela se produit si les valeurs des champs d'un objet sont stockées dans des registres. Le programme peut alors accéder aux registres à la place de l'objet et ne plus jamais y accéder. Cela impliquerait que l'objet est des ordures.
L'objet est accessible s'il peut être impliqué dans un calcul continu éventuel. Par conséquent, si votre code fait référence à une variable locale et que rien d’autre n’y fait référence, vous pouvez provoquer la collecte de l’objet en lui attribuant la valeur null. Cela donnerait une exception de pointeur null, ou changerait le comportement de votre programme, ou s'il ne le faisait pas, vous n'aviez pas besoin de la variable en premier lieu.
Si vous annulez un champ ou un élément de tableau, cela peut sembler logique pour certaines applications et la récupération de la mémoire sera plus rapide. Une fois que la casse crée un grand tableau pour remplacer un tableau existant référencé par un champ dans une classe - si le champ est annulé avant la substitution, il peut soulager la mémoire.
Une autre caractéristique intéressante de Java est que la portée n'apparaît pas dans les fichiers de classe. Par conséquent, la portée n'est pas pertinente pour l'accessibilité. ces deux méthodes créent le même bytecode, et donc VM ne voit pas du tout la portée de l'objet créé:
static void withBlock () {
int x = 1;
{
Object a = new Object();
}
System.out.println(x+1);
}
static void withoutBlock () {
int x = 1;
Object a = new Object();
System.out.println(x+1);
}
Pas nécessairement. Un objet devient éligible pour le garbage collection quand il n'y a plus de threads actifs contenant une référence à l'objet.
Les variables locales sortent du champ d'application lorsque la méthode est renvoyée et il est illogique de définir les variables locales sur null. Les variables disparaissent de toute façon. S'il n'y a rien d'autre qui contienne une référence aux objets auxquels les variables font référence, ces objets deviennent éligible pour la collecte des ordures.
L'important n'est pas de regarder uniquement les variables, mais de regarder les objets auxquels ces variables font référence et de déterminer où ces objets sont référencés par votre programme.
Cela est inutile pour les variables locales, mais cela peut être utile/nécessaire pour clarifier les variables d'instance qui ne sont plus nécessaires (par exemple, après l'initialisation).
(Ouais ouais, je sais comment appliquer le motif Builder ...)
Cela ne pourrait faire que some sens dans certains cas de ce genre:
public void myHeavyMethod() {
List hugeList = loadHugeListOfStuff(); // lots of memory used
ResultX res = processHugeList(hugeList); // compute some result or summary
// hugeList = null; // we are done with hugeList
...
// do a lot of other things that takes a LOT of time (seconds?)
// and which do not require hugeList
...
}
Ici, il pourrait présente certains avantages pour supprimer la mise en commentaire de la ligne hugeList = null
, je suppose.
Mais il serait certainement plus logique de réécrire la méthode (peut-être refactoriser en deux, Ou spécifier une portée interne).
Définir une référence d'objet sur null ne la rend/éligible pour le garbage collection. Elle ne libère pas nécessairement la mémoire, ce qui dépend du moment où le garbage collector s'exécute (ce qui dépend de la machine virtuelle Java). .] Lorsque le ramasse-miettes est exécuté, il libère le tas en supprimant uniquement les objets qui sontéligible pour le ramasse-miettes.