Le dernier article a présenté les connaissances pertinentes du modèle de mémoire JVM. En fait, certains contenus peuvent être introduits plus en profondeur, comme l'insertion dynamique de pools constants au moment de l'exécution, la mémoire directe, etc. Il est temps d'améliorer le blog précédent plus tard. Venez aujourd'hui Présentez quelques stratégies de récupération de place dans JVM.
1. La méthode finishize() Lorsque l'objet n'a aucune référence, l'objet sera généralement recyclé, mais que se passe-t-il si l'on souhaite effectuer certaines opérations avant que l'objet ne soit recyclé, comme fermer certaines ressources, ou ressusciter l'objet pour éviter qu'il ne soit recyclé ? C'est à ce moment-là que la méthode finalize est utilisée. La méthode finalize est une méthode définie dans la classe Object, ce qui signifie que tout objet possède cette méthode. Mais cette méthode ne sera appelée qu'une seule fois. Si l'objet meurt à nouveau après avoir été ressuscité, la méthode finalize ne sera pas appelée lorsque l'objet sera recyclé pour la deuxième fois, et la priorité est relativement faible, et il n'y a aucune garantie qu'elle le sera. être exécuté, il n'est donc pas recommandé d'utiliser la méthode finalize. Pour résumer, il y a 3 fonctionnalités : ① GC a été appelé auparavant. ②. Il ne sera appelé qu'une seule fois. ③ Il n'est pas fiable et son exécution ne peut pas être garantie. Il n'est pas recommandé d'utiliser
. Concernant la façon d'utiliser finalize, reportez-vous au code suivant :1 public class FinalizeTest { 2 3 private static FinalizeTest test; 4 /** 5 * VM参数:-XX: +PrintGCDetails -Xmx=1M -Xms=1M 6 * 7 * @param args 8 */ 9 public static void main(String[] args) { 10 //先对test对象赋值 11 test = new FinalizeTest(); 12 int _1m = 1024 * 1024; 13 //将test置为null,便于回收 14 test = null; 15 try { 16 System.gc(); 17 //模拟睡眠5s,finalize优先级较低,保证finalize能执行 18 Thread.sleep(5000); 19 } catch (InterruptedException e) { 20 e.printStackTrace(); 21 } 22 if (test != null) { 23 System.out.println("first,i am alive"); 24 }else{ 25 System.out.println("first,i am dead"); 26 } 27 //由于test在finalize方法里复活了,再次将test置为null 28 test = null; 29 try { 30 System.gc(); 31 Thread.sleep(5000);//模拟睡眠5s,让GC回收 32 } catch (InterruptedException e) { 33 e.printStackTrace(); 34 } 35 if (test != null) { 36 System.out.println("second,i am alive"); 37 }else{ 38 System.out.println("second,i am dead"); 39 } 40 41 } 42 @Override 43 protected void finalize() throws Throwable { 44 test = this ; 45 System.out.println("finalize excuted"); 46 super.finalize(); //调用父类的finailize方法 47 } 48 }
Le résultat de l'exécution de ce code est le suivant :
Vous pouvez le voirUne fois la méthode finalize exécutée, l'objet de test est réactivé, donc d'abord, je suis vivant est imprimé. Mais lors du deuxième GC, la méthode finalize n'a pas été exécutée, donc le deuxième, je suis mort, a été imprimé. Comme mentionné précédemment, finalize a une faible priorité et n'est pas fiable. S'il n'y a pas de Thread.sleep(5000), regardons le code et les résultats :
<.>
1 public class FinalizeTest { 2 3 private static FinalizeTest test; 4 /** 5 * VM参数:-XX: +PrintGCDetails -Xmx=1M -Xms=1M 6 * 7 * @param args 8 */ 9 public static void main(String[] args) { 10 //先对test对象赋值 11 test = new FinalizeTest(); 12 int _1m = 1024 * 1024; 13 //将test置为null,便于回收 14 test = null; 15 try { 16 System.gc(); 17 //模拟睡眠5s,finalize优先级较低,保证finalize能执行 18 //不执行睡眠操作,Thread.sleep(5000); 19 } catch (Exception e) { 20 e.printStackTrace(); 21 } 22 if (test != null) { 23 System.out.println("first,i am alive"); 24 }else{ 25 System.out.println("first,i am dead"); 26 } 27 //由于test在finalize方法里复活了,再次将test置为null 28 test = null; 29 try { 30 System.gc(); 31 //不执行睡眠操作,Thread.sleep(5000);//模拟睡眠5s,让GC回收 32 } catch (Exception e) { 33 e.printStackTrace(); 34 } 35 if (test != null) { 36 System.out.println("second,i am alive"); 37 }else{ 38 System.out.println("second,i am dead"); 39 } 40 41 } 42 @Override 43 protected void finalize() throws Throwable { 44 test = this ; 45 System.out.println("finalize excuted"); 46 super.finalize(); //调用父类的finailize方法 47 } 48 }Les résultats d'exécution sont les suivants :
On voit clairement ici que la priorité de la méthode finalize est relativement faible.
Réflexion sur cet exemple : Le premier morceau de code de cet exemple est implémenté en référence au code dans "Compréhension approfondie de la machine virtuelle Java", mais j'ai toujours l'impression qu'il y a deux questions : Pourquoi l'objet de test modifié avec des variables membres statiques existe-t-il ? S'il s'agit d'une modification statique, alors il existe une zone de méthode et l'effet GC dans la zone de méthode n'est généralement pas très bon. L'autre existe sous forme de variables membres, de sorte que lorsque la finalisation est recyclée, elle ne reflète pas le recyclage de l'objet actuel lui-même, donc j'estime que cet exemple n'est pas très bon.
2. Méthode de comptage de référencesLa méthode de comptage de références est un algorithme de recyclage GC antérieur, qui n'est généralement pas utilisé à l'heure actuelle. Oui :
Chaque objet maintient un compteur de référence avec une valeur initiale de 0. Lorsqu'un objet est référencé, le compteur de référence de l'objet est incrémenté de 1. Lorsqu'il n'est pas référencé, le compteur de référence de l'objet est décrémenté de 1. le compteur de référence d'un objet devient 0, l'objet est considéré comme recyclable. Les avantages et les inconvénients de l'utilisation de cette méthode sont évidents. Les avantages sont une mise en œuvre simple et une grande efficacité. L'inconvénient est qu'il peut y avoir des références circulaires, conduisant à un débordement de mémoire.
3. Méthode de marquageMark - La méthode de compensation est divisée en deux étapes : "marquage" et "effacement" selon le nom. L'idée de base est la suivante :
Marquez d'abord tous les objets survivants. Une fois le marquage terminé, tous les objets marqués sont effacés uniformément. Alors comment déterminer si un objet peut être recyclé ? Pendant le GC, le parcours commence à partir d'une série de nœuds racine GC Roots. Le chemin parcouru pendant le parcours est appelé chaîne de référence. Si un objet n'a aucune chaîne de référence liée aux racines GC, alors l'objet n'est pas disponible et le sera. jugé disponible Recyclage, cet algorithme est également appelé algorithme de recherche racine. Alors, quels objets peuvent devenir des objets GC Roots ? Dans le langage Java, l'objet du GC ROOTS comprend les 4 types suivants : Les variables citées dans la pile de la machine virtuelle L'objet des attributs statiques dans la zone méthode
Objets référencés par des constantes dans la zone méthodeObjet référencé par JNI (méthode native) dans la pile de méthodes locale
Le schéma algorithmique de la méthode mark-and-clear est le suivant :
Remarque : cet article L'image de l'algorithme de recyclage GC est transférée de l'article d'un internaute (cliquez ici). Le contenu de l'image de l'internaute est également cohérent avec l'œuvre originale, mais la couleur est différente.
4. Méthode de copie de la nouvelle génération
L'idée de base dela méthode de copie est : Diviser le mémoire en 2 blocs de taille égale, un seul d'entre eux est utilisé à la fois Pendant le GC, tous les objets survivants sont copiés dans une autre zone à chaque fois, puis la mémoire est nettoyée .
Ce sont tous des objets de référence dans la zone de méthode et la pile. Les avantages de la méthode de copie sont : une mise en œuvre simple, un recyclage rapide et aucune fragmentation de la mémoire. Cependant, comme un seul bloc est utilisé à la fois, l'utilisation de la mémoire est faible. Le diagramme schématique de l'algorithme de réplication est le suivant :
Recommandations associées :
algorithme de récupération de place jvm
Partagez le Résumé de l'apprentissage du mécanisme de récupération de place Java
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!