Lorsque le programme crée des entités de type référence telles que des objets, des tableaux, etc., le système alloue un morceau de mémoire à l'objet dans la mémoire du tas, et l'objet est stocké dans ce morceau de mémoire. Lorsque ce morceau de mémoire n'est plus référencé par aucune variable de référence, le morceau de mémoire devient des ordures, en attendant que le mécanisme de collecte des ordures soit recyclé. Le mécanisme de collecte des ordures a trois caractéristiques:
Le mécanisme de collecte des ordures n'est responsable que du recyclage des objets dans la mémoire du tas et ne recyclera aucune ressource physique (tels que les connexions de base de données, les ressources de fichier ouvrir, etc.), ni ne recycler la mémoire allouée à l'objet d'une manière autre que la manière de créer un objet, (comme la mémoire appliquée par l'objet appelant Malloc dans la méthode locale)
Le programme ne peut pas contrôler avec précision le fonctionnement de la collecte des ordures, il ne peut donc être recommandé que pour la collecte des ordures. Il existe deux méthodes recommandées: System.gc () et runtime.getRuntime (). GC ()
Avant la collecte des ordures, sa méthode finaliser () sera toujours appelée d'abord, mais elle est la même que le temps de collecte des ordures, et la méthode finaliser () n'est pas non plus sûre.
En ce qui concerne les trois caractéristiques ci-dessus, il y a trois problèmes:
1. Le travail de nettoyage doit être fait manuellement pour libérer la mémoire et d'autres ressources physiques allouées d'une manière autre que la manière de créer des objets. Et veillez à éliminer les références d'objets expirées, sinon l'OOM peut être causée.
Le nettoyage manuel utilise généralement une structure de code comme essayer ... enfin ...
Les exemples sont les suivants:
import java.io.fileInputStream; import java.io.filenotfoundException; import java.io.ioException; public class manualclear {public static void main (string [] args) {fileInputStream fileInputStream = null; essayez {fileInputStream = new FileInputStream ("./ src / manualclear.java"); } catch (filenotfoundException e) {System.out.println (e.getMessage ()); e.printStackTrace (); retour; } try {byte [] bbuf = new byte [1024]; int hasread = 0; try {while ((hasread = fileInputStream.read (bbuf))> 0) {System.out.println (new String (bbuf, 0, hasread)); }} catch (ioException e) {e.printStackTrace (); }} enfin {try {fileInputStream.close (); } catch (ioException e) {e.printStackTrace (); }}}}Il y a généralement trois cas d'OOM courants causés par une référence aux objets expirés. Ces trois cas ne sont généralement pas faciles à détecter, et il n'y aura aucun problème à fonctionner dans un court laps de temps. Cependant, après une longue période, le nombre d'objets divulgués entraînera éventuellement le plan du programme.
Lorsque la classe gère la mémoire par elle-même, vous devez vous méfier des fuites de mémoire comme suit:
Importer java.util.arrays; import java.util.emptystacKexception; classe de classe {objet privé [] éléments; Taille INT privée; private static final int default_inital_capacity = 16; public stack () {elements = nouvel objet [default_inital_capacity]; } public void push (objet e) {Assurecapacity (); éléments [taille ++] = e; } Objet public pop () {if (size == 0) {Throw New videStacKexception (); } Return Elements [- Size]; } private void assurecapacity () {if (elements.length == taille) {elements = arrays.copyof (elements, 2 * taille + 1); }}} classe publique StackDemo {public static void main (String [] args) {stack stack = new Stack (); for (int i = 0; i <10000; i ++) {stack.push (new object ()); } pour (int i = 0; i <10000; i ++) {stack.pop (); }}}La raison des fuites de mémoire est que même si d'autres objets de la pile ne sont plus référencés, le tableau des éléments [] dans la classe de pile contient toujours des références à ces objets, ce qui entraîne les objets qui ne sont pas recyclés par la collecte des ordures. Par conséquent, lorsque la classe doit gérer la mémoire par elle-même, méfiez-vous de savoir si ces références expirées maintenues en interne sont déréférencées dans le temps. Dans cet exemple, seulement après la sortie de la pile, celui affiché sera affiché.
éléments [taille] = null;
Le cache doit se méfier des fuites de mémoire. Cette situation est généralement le cas qu'une fois l'objet mis dans le cache, il est probable qu'il est facile d'oublier s'il n'est pas utilisé pendant longtemps. Habituellement, WakehashMap peut être utilisé pour représenter le cache. Après l'expiration des éléments du cache, ils peuvent être automatiquement supprimés. Ou il peut être exécuté périodiquement par un thread d'arrière-plan pour effacer les éléments expirés dans le tampon.
L'enregistrement des auditeurs ou des rappels est mieux affiché pour se désinscrire.
2. Ne pas appeler finaliser () manuellement, il est appelé au collecteur des ordures
3. Évitez d'utiliser la méthode finaliser () à moins qu'elle ne soit utilisée comme un jugement de la condition finale pour constater que l'objet n'a pas été correctement nettoyé; Il est utilisé comme réseau de sécurité pour nettoyer les ressources système lorsqu'il est nettoyé manuellement les appels oubliés. Le nettoyage retardé ne doit pas être nettoyé. Si vous enregistrez les informations sur la ressource de nettoyage oubliée en même temps, il est également pratique de découvrir les erreurs plus tard et de modifier le code de nettoyage oublié à temps; Libérez les ressources système non critiques obtenues par la méthode locale dans l'objet.
Étant donné que la méthode finalisée () n'est pas assurée avec précision, il est préférable de ne pas publier des ressources clés, mais peut être utilisée dans les trois cas mentionnés ci-dessus. Le premier cas est le suivant:
classe de classe {boolean Checkout = false; Livre public (booléen Checkout) {this.Checkout = Checkout; } public void checkin () {Checkout = false; } @Override Protected void finalize () lance Throwsable {if (Checkout) {System.out.println ("Error: Check Out"); }}} classe publique finizeCheckObjectUse {public static void main (String [] args) {new book (true); System.gc (); }}Résultats de l'exécution:
Erreur: consulter
L'objet de livre dans l'exemple doit être dans l'état de contrôle avant d'être libéré, sinon il ne peut pas être publié. L'implémentation dans Finalize peut aider à découvrir des objets illégaux dans le temps, ou plus directement, à utiliser une variable de référence pour y référer directement dans Finalize, afin qu'il puisse rentrer à l'état d'accessible, puis le traiter à nouveau.
Un autre point à noter est que si la sous-classe remplace la méthode Finalize de la classe parent, mais oublie d'appeler manuellement super.finalize ou le processus finalisé de la sous-classe a une exception, ce qui entraîne une super.finalze non exécutée, alors la méthode finale de la classe parent ne sera jamais appelée.
comme suit:
class Parent {@Override Protected void finalize () lève le throwable {System.out.println (getClass (). getName () + "finaliser le démarrage"); }} class Son étend le parent {@Override Protected void finalize () lève le throwable {System.out.println (getClass (). getName () + "finaliser start"); }} classe publique Superfinalizelost {public static void main (String [] args) {new Son (); System.gc (); }}Résultats en cours:
Fils finaliser le début
ou
class Parent {@Override Protected void finalize () lève le throwable {System.out.println (getClass (). getName () + "finaliser le démarrage"); }} class Son étend le parent {@Override Protected void finalize () lève le throwable {System.out.println (getClass (). getName () + "finaliser start"); int i = 5/0; super.finalize (); }} classe publique Superfinalizelost {public static void main (String [] args) {new Son (); System.gc (); }}Résultats de l'exécution:
Fils finaliser le début
Pour le deuxième cas, vous pouvez utiliser la structure Try ... Enfin ... pour le résoudre, mais pour le premier cas, il est préférable d'utiliser une méthode appelée End Method Guardian. L'exemple est le suivant
class Parent2 {private final objet finalizeGuardian = new object () {protected void finalize () lève le throwable {System.out.println ("Exécuter la logique dans la méthode de terminaison de la classe parent ici"); }; };} class Son2 étend Parent2 {@Override Protected void finalize () lance Throwsable {System.out.println (getClass (). getName () + "finalize start"); int i = 5/0; super.finalize (); }} classe publique finalizeguardian {public static void main (String [] args) {new Son2 (); System.gc (); }}Résultats de l'exécution:
Exécutez la logique dans la méthode de terminaison de classe parent ici
SON2 Finalize Start
Cela garantit que les opérations requises dans la méthode finale de la classe parent sont exécutées.
Ce qui précède concerne cet article, j'espère qu'il sera utile à l'apprentissage de tout le monde.