En tant que programmeur, le processus de formation est comme le protagoniste d'un roman fantastique. Non seulement il nécessite la pratique de divers arts martiaux, mais la culture de l'énergie intérieure est tout aussi importante. Bien que les arts martiaux puissent rapidement améliorer la force du protagoniste, si l'énergie intérieure est trop faible, il est impossible d'exercer un dixième des arts martiaux.
Par conséquent, après avoir introduit des compétences externes telles que les modèles de conception, LZ est directement passé à la pratique interne du Qi et a discuté du contenu de JVM avec tous les amis singes.
À l'origine, ce chapitre devrait présenter du contenu lié à GC, mais avant cela, LZ va discuter avec vous d'une petite astuce de programmation. Bien sûr, cette petite astuce est en réalité étroitement liée au GC.
Je ne sais pas si l'un d'entre vous a lu des articles liés à la mémoire JAVA lorsqu'ils répertorient des suggestions, ils écrivent souvent une telle suggestion.
Article XX : Après avoir utilisé l'objet, veuillez définir explicitement l'objet sur null.
Les mots originaux ne sont peut-être pas comme ça, mais le sens est le même. La signification décrite dans les mots est que nous devrions écrire de cette façon lors de l'écriture de code à l'avenir.
Object obj = new Object(); //to do something obj = null;
Ce code a un peu de style C/C. obj=null remplace delete obj ou free(obj) en C/C, ce qui revient à nous rappeler que même avec GC, on aime juste. il n'y a pas de GC, l'objet doit se voir attribuer une valeur nulle après l'avoir utilisé.
Tout d'abord, ce que LZ veut expliquer ici, c'est qu'attribuer à obj une valeur nulle est en fait très différent de delete en C/C. La raison pour laquelle LZ dit qu'ils remplacent delete et free est simplement parce qu'ils apparaissent dans le fichier. code Les positions dans sont tout simplement similaires.
obj=null ne fait qu'une chose, c'est de déconnecter la variable de référence obj de l'instance créée par new Object(). En fait, l'espace mémoire occupé par l'instance n'est toujours pas libéré.
Lorsque cette suggestion a été faite, l'intention initiale de nombreux blogueurs ou auteurs de livres (car de nombreux blogueurs la lisent probablement dans des livres) était d'éliminer le plus rapidement possible l'association entre les références et les instances, incitant ainsi GC à procéder pendant les ordures. collection, la mémoire occupée par l’instance est libérée. Dans certains cas, cela est également fait pour éliminer les fuites de mémoire.
LZ estime personnellement que l'intention initiale de nombreux blogueurs ou auteurs de livres de faire cette suggestion s'adresse principalement aux programmeurs qui n'ont pas été exposés aux principes du GC et à la gestion de la mémoire, car sans comprendre les connaissances pertinentes, il est facile de ne pas comprendre la portée des variables, ce qui entraîne un gaspillage inutile de mémoire (je pense personnellement que ce n'est pas le but principal, car tant qu'aucune fuite de mémoire ne se produit, la mémoire finira par être libérée par GC), voire des fuites de mémoire.
Donc, par souci de sécurité, certains experts ont fait une telle suggestion.
Compte tenu de cela, LZ estime personnellement qu'une fois que tout le monde a maîtrisé les connaissances pertinentes, vous pouvez complètement ignorer cette suggestion, ce qui réduira évidemment la clarté du code et augmentera la charge de codage. Les échanges sont uniquement destinés à éviter des fuites de mémoire qui peuvent même ne pas exister.
Voici une explication des raisons pour lesquelles le fait de ne pas attribuer une valeur nulle à un objet peut parfois provoquer des fuites de mémoire. Considérons le morceau de code suivant.
import java.util.Arrays; public class Stack { private static final int INIT_SIZE = 10; private Object[] datas; private int size; public Stack() { super(); datas = new Object[INIT_SIZE]; } public void push(Object data){ if (size == datas.length) { extend(); } datas[size++] = data; } public Object pop(){ if (size == 0) { throw new IndexOutOfBoundsException("size is zero"); } return datas[--size]; } private void extend(){ datas = Arrays.copyOf(datas, 2 * size + 1); } }
Ce code est une implémentation de pile simple avec une longueur évolutive. Lorsque vous écrivez un code de test pour le tester, vous constaterez qu'il n'a aucun problème. Mais désolé, il y a ici une "fuite de mémoire" évidente, provoquée par le fait que certains objets ou références ne sont pas définis sur des valeurs nulles.
Si vous ne l'avez pas encore vu, LZ vous fera un petit rappel et vous vous en rendrez compte. Dans ce code, les objets du tableau ne grandiront qu'à l'infini et ne diminueront pas à mesure que les éléments de la pile seront éclatés. Ce qui diminue, c'est uniquement la taille de la pile affichée en externe. Prenons un scénario extrême : supposons que vous ayez placé 1 million d'objets dans la pile et que finalement 999 999 soient utilisés. De l'extérieur, il ne reste qu'un seul objet disponible dans la pile, mais notre pile contient toujours des références à 1 million d'objets. Si la JVM pouvait survivre, elle vous ravagerait définitivement.
Ce qui nous manque, c'est l'étape d'attribution à l'objet d'une valeur nulle, donc la méthode pop doit être remplacée par la méthode suivante, et vous pouvez jeter un œil au code source de la méthode Remove dans ArrayList, qui a un idée similaire.
public Object pop(){ if (size == 0) { throw new IndexOutOfBoundsException("size is zero"); } Object data = datas[--size]; datas[size] = null; return data; }
这个内存泄露是非常隐蔽的,而且实际使用当中不一定就能发现,因为随着Stack对象的回收,整个数组也会被回收,到时内存泄露就被掩盖了。
所以个人觉得上述的那个建议是完全没有必要的,就算遵从了上面的建议,如果对内存管理不熟悉的话,也不会想到上面这个代码中的问题。如果想彻底的避免内存泄露的发生,机械式的主动将对象赋为空值,并不是一个可以从根本上解决问题的办法。
真正能够解决问题的办法,就是掌握好GC的策略与原理,定义一个变量时多注意变量的作用域,如此才可以更好的避免内存泄露。
所以学好GC原理还是很有必要的,希望准备走JAVA之路的朋友,尤其是从培训机构出来的猿友们(此处没有鄙视培训机构出来的猿友们的意思,因为LZ本人也是半路出家,从培训机构走上编程之路的程序猿之一),一定不要只专注于各个框架的使用以及业务的深入,虽然这些事很有必要,但并不是全部。
follow me and go the memory world 吧(语法都是浮云)。
以上就是JVM内存管理------杂谈(借此也论一论obj=null)的内容,更多相关内容请关注PHP中文网(www.php.cn)!