Étape 10 : Résumé du sujet (Chapitre 3 : Machine Virtuelle)

Chapitre 3 : Machine virtuelle

1.Structure de la mémoire JVM

Exiger

  • Division principale de la structure de la mémoire JVM
  • En particulier, vous devez connaître la relation entre la zone de méthode, la génération permanente et le métaespace.

Comprendre le partitionnement de la mémoire basé sur l'exécution d'un morceau de code Java
Insérer la description de l'image ici

  • Exécutez la commande javac pour compilercode sourcepourbytecode
  • Exécuter la commande Java
    1. Créer une JVM (Machine virtuelle Java),transfertSous-système de chargement de classeclasse de charge (fichier de bytecode), stocke les informations d'origine de la classe (nom de la classe, relation d'héritage, variables membres, noms des autres classes référencées, codes de méthode de la classe)zone de méthode(Lire les fichiers de bytecode du disque vers la mémoire)
    2. créerfil principal, la zone mémoire utilisée estPile de machines virtuelles JVM, commencez à exécuter la méthode principale
    3. Si une classe invisible est rencontrée, le processus de chargement de classe continuera à être déclenché et sera également stocké dans la zone de méthode .
    4. Pour les objets qui doivent être créés par la nouvelle action, utiliseztasmémoire à stocker
    5. Les objets qui ne sont plus utilisés seront remplacés parÉboueur(GC) récupère sa mémoire lorsqu'elle manque de mémoire
    6. Lors de l'appel d'une méthode, leVariables locales, paramètres de méthodeCe qui est utilisé, c'est la pile de machines virtuelles JVMempilerMémoire
    7. Lorsque vous appelez une méthode, allez d'abord danszone de méthodeObtenez les instructions de bytecode de la méthode, eninterprèteInterpréter les instructions de bytecode en code machine pour exécution
    8. Lors de l'appel d'une méthode, lisez le numéro de ligne d'instruction exécutéecompteur de programme, si un changement de fil se produit, vous pouvez continuer à partir de la position interrompue lors de la reprise.
    9. Pour les appels de méthodes implémentés non Java (méthodes natives), l'utilisation de la mémoire est appeléepile de méthodes natives(voir description); les méthodes Java ordinaires utilisentPile de machines virtuelles
    10. Pour les appels de méthode hotspot ou le code en boucle fréquemment, le JITCompilateur juste à tempsCompilez ces codes dans le cache de code machine pour améliorer les performances d'exécution

illustrer

  • La police en gras représente les composants de la machine virtuelle JVM
  • Pour l'implémentation de la machine virtuelle Hotspot d'Oracle, il n'y a aucune distinction entre la pile de machines virtuelles et la pile de méthodes locales.

Zones où un débordement de mémoire peut se produire (épuisement de la mémoire)

  • Zones où le débordement de mémoire ne se produira pascompteur de programme
  • OutOfMemoryError (erreur de mémoire insuffisante) se produit
    • Mémoire de tas épuisée– Il y a de plus en plus d’objets, ils sont utilisés tout le temps et ils ne peuvent pas être collectés.
    • Mémoire de la zone de méthode épuisée– De plus en plus de classes sont chargées et de nombreux frameworks généreront dynamiquement de nouvelles classes pendant l'exécution.
    • Accumulation de pile de machines virtuelles– Chaque thread occupera jusqu'à 1 Mo de mémoire, et le nombre de threads augmente et s'exécute longtemps sans être détruit.
  • Zone où se produit StackOverflowError
    • Pile de machines virtuelles JVM, la raison est que l'appel récursif de la méthode (dans le thread) ne s'est pas terminé correctement (Trop d'appels de méthode)、Référence circulaire lors de la désérialisation de JSON

Zone méthode, génération permanente, métaespace

  • Zone méthode : (C'est une norme, c'est une définition) est une zone mémoire définie dans la spécification JVM.utilisé pour stocker les coursMétadonnées, bytecode de méthode, informations requises par le compilateur juste à temps, etc.
  • Génération permanente : (Implémentation de la zone méthode dans différentes versions Java) est l'implémentation par la machine virtuelle Hotspot de la spécification JVM (avant 1.8)
  • Métaespace : (Implémentation de la zone méthode dans différentes versions Java) est une autre implémentation de la spécification JVM par la machine virtuelle Hotspot (après 1.8),Utiliser la mémoire locale comme espace de stockage pour ces informations

Présentez seulementmétaespace
Insérer la description de l'image ici

Apprenez trois choses de cette image

  • Lorsqu'une classe est utilisée pour la première fois, elle estchargeur de classeLisez les méta-informations de classe du fichier de classe et stockez-les dans le méta-espace
  • Les métainformations de classe de X et Y sont stockées dans le métaespace et ne sont pas accessibles directement.
  • Vous pouvez utiliser X.class, Y.class (instance) pour accéder indirectement aux méta-informations de classe, les deux appartiennent à des objets Java et peuvent être utilisés dans notre code

Insérer la description de l'image ici

Que peut-on apprendre de cette image

  • Dans la mémoire tas : lorsque tous les objets d'instance correspondant à tous les objets de classe chargés par un objet chargeur de classe ne sont pas référencés, la mémoire tas occupée par eux sera libérée lors du GC.
  • Dans le métaespace : La libération de mémoire est exprimée en unités du chargeur de classe . Lorsque la mémoire du chargeur de classe dans le tas est libérée, les métainformations de classe correspondantes dans le métaespace sont également libérées.

2.Paramètres de mémoire JVM

Exiger

  • Être familier avec les paramètres JVM courants, notamment ceux liés à la taille

Mémoire de tas, définie par taille

Insérer la description de l'image ici

expliquer:

  • -Xms Mémoire de tas minimale(Y compris nouvelle génération et ancienne génération)
  • -Xmx Mémoire de tas maximale(Y compris nouvelle génération et ancienne génération)
  • Il est généralement recommandé de définir -Xms et -Xmx pour qu'ils soient de taille égale, c'est-à-dire qu'il n'est pas nécessaire de réserver de la mémoire et qu'il n'est pas nécessaire de passer de petit à grand, les performances sont donc meilleures.
  • -XX : NewSizeet -XX :MaxNewSize Définir les valeurs minimales et maximales de la nouvelle génération, mais il n'est généralement pas recommandé de le définir. Il est contrôlé par la JVM elle-même.
  • -Xmninstallationmémoire nouvelle génération, équivalent à définir -XX:NewSize et -XX:MaxNewSize en même tempset ont des valeurs égales
  • La rétention signifie qu'elle n'occupera pas autant de mémoire au début. Au fur et à mesure que de plus en plus de mémoire sera utilisée, cette partie de la mémoire réservée sera progressivement utilisée. Le même ci-dessous

Mémoire de tas, définie proportionnellement
Insérer la description de l'image ici

expliquer:

  • -XX : NewRatio=2:1 signifieAncienne génération : Nouvelle génération;(La valeur par défaut est 2:1
  • -XX : SurvivorRatio=4:1 (Jardin d'Eden : à partir de); signifie que la nouvelle génération est divisée en six parties, le Jardin d'Eden occupe quatre parties, et de et vers chacun occupe une partie; (La valeur par défaut est 8:1
  • from = to
  • Survivor = from + to

Q :
Concernant les paramètres de configuration de la mémoire JVM : -Xmx10240m -Xms10240m -Xmn5120m -XX:SurvivorRatio=3 la valeur minimale de la mémoire et la taille totale de la zone Survivant sont respectivement

  • Valeur mémoire minimale : -Xmn divisé par 5 ;
  • La taille totale de la zone Survivant = de + à = -Xmn divisée par 5 puis multipliée par 2 ;

Paramètres de mémoire métaespace
Insérer la description de l'image ici

expliquer:

  • class spaceInformations de base sur la classe de stockage, la valeur maximale est contrôlée par -XX:CompressedClassSpaceSize
  • non-class spaceStockez d'autres informations en plus des informations de base de la classe (telles que le bytecode de méthode, les annotations, etc.)
  • La taille totale de l'espace de classe et de l'espace hors classe est -XX:MaxMetaspaceSizecontrôlée par , la valeur par défaut est 1G

Avis:

  • Ici -XX:CompressedClassSpaceSize, cet espace est également lié à l'activation ou non de la compression du pointeur. Nous n'entrerons pas dans les détails ici. Vous pouvez simplement penser que la compression du pointeur est activée par défaut.

Paramètres de mémoire cache du code
Insérer la description de l'image ici

expliquer:

  • Si -XX:ReservedCodeCacheSize < 240m, tout le code machine optimisé existe ensemble sans discernement
  • Sinon, il est divisé en trois zones (il y a une faute de frappe dans l'image, la méthode est mal orthographiée et il manque un e)
    • non-nmethods- Code utilisé par la JVM elle-même
    • profiled nmethods- Code machine partiellement optimisé
    • non-profiled nmethods- Code machine entièrement optimisé

Paramètres de mémoire de thread
La mémoire occupée par chaque thread (pile de machine virtuelle) ;
Insérer la description de l'image ici

Document officiel de référence

  • https://docs.oracle.com/en/java/javase/11/tools/java.html#GUID-3B1CE181-CD30-4178-9602-230B800D4FAE

3.Collecte des ordures JVM

Exiger

  • Maîtriser l'algorithme de garbage collection
  • Maîtriser l'idée du recyclage générationnel
  • Comprendre le marquage tricolore et le traitement des marques manquantes
  • En savoir plus sur les éboueurs courants

Trois algorithmes de garbage collection

Méthode Mark-and-Sweep (n'est plus utilisée maintenant, présente de nombreux problèmes de fragmentation)
Insérer la description de l'image ici

expliquer:

  1. Rechercher GC Root 对象(objets racine), c'est-à-dire ceuxDes objets qui ne seront jamais recyclés,commeObjets référencés par des variables locales de la méthode en cours d'exécution et objets référencés par des variables statiques
  2. marquer l'étapeLe long de la chaîne de référence de l'objet GC Root, marquez les objets référencés directement ou indirectement.
  3. phase de nettoyage: Libère la mémoire occupée par les objets non taggés

Points clés:

  • La vitesse de marquage a une relation linéaire avec les objets survivants
  • La vitesse d'effacement est linéairement liée à la taille de la mémoire
  • L'inconvénient est que cela entraînera une fragmentation de la mémoire.

Méthode de tri par marquage (adaptée au ramassage des ordures de l'ancienne génération)

Insérer la description de l'image ici

expliquer:

  1. La phase de marquage et la phase de nettoyage précédentes sont similaires à la méthode de marquage et de nettoyage.
  2. Il existe une étape supplémentaire de tri, en déplaçant les objets survivants vers une extrémité pour éviter la fragmentation de la mémoire.

Caractéristiques:

  • La vitesse de marquage a une relation linéaire avec les objets survivants
  • La vitesse de nettoyage et de tri est linéairement liée à la taille de la mémoire
  • L'inconvénient est que les performances sont plus lentes

Méthode de copie marquée (adaptée au garbage collection de la nouvelle génération (moins d'objets survivants))

Insérer la description de l'image ici
expliquer:

  1. Divisez toute la mémoire en deux zones de taille égale, depuis et vers, où est toujours libre et depuis stocke les objets nouvellement créés
  2. La phase de marquage est similaire à l'algorithme précédent
  3. Après avoir trouvé les objets survivants, ils seront copiés de la zone de vers la zone vers. La défragmentation est naturellement terminée pendant le processus de copie.
  4. Une fois la copie terminée, échangez simplement les positions de et vers

Caractéristiques:

  • Les vitesses de marquage et de copie sont linéairement liées aux objets survivants
  • L'inconvénient est qu'il prend deux fois plus de place

GC et algorithme de collecte générationnelle

GCLe but est d'atteindreLibération automatique de la mémoire des objets inutiles,Réduisez la fragmentation de la mémoire et accélérez l’allocation

Points clés du GC :

  • La zone de recyclage estMémoire de tas, à l'exclusion de la pile de machines virtuelles
  • Pour déterminer les objets inutiles, utilisezAlgorithme d'analyse d'accessibilité, méthode de marquage tricoloreMarquez les objets vivants et recyclez les objets non marqués
  • L'implémentation spécifique de GC est appeléeÉboueur
  • GC utilise principalementIdées de recyclage générationnelles
    • La base théorique est que la plupart des objets vont et viennent, sont détruits immédiatement et peuvent être recyclés immédiatement après utilisation. Il existe également un petit nombre d'objets qui survivent longtemps et sont difficiles à recycler à chaque fois.
    • Selon les caractéristiques de ces deux types d'objets, la zone de recyclage est divisée ennouvelle génération(les objets vont et viennent) etvieillesse(Survie, difficile de recycler à chaque fois),La nouvelle génération utilise la méthode de copie des marques, et l'ancienne génération utilise généralement la méthode de tri des marques.
  • Selon l'échelle du GC, il peut être divisé en GC mineur , GC mixte et GC complet.

    GC mineur : un garbage collection a eu lieu dans la nouvelle génération, qui est un garbage collection à petite échelle ;
    Full GC : la nouvelle génération et l'ancienne génération n'ont pas suffisamment de mémoire et un garbage collection complet sera effectué. Cela prendra du temps le temps et les pauses évidentes du système se feront sentir ;
    GC mixte : la collecte des déchets se produit dans la nouvelle génération, et la collecte des déchets se produit également dans certaines anciennes générations. Ceci est unique au garbage collector G1 ;

Recyclage générationnel

  1. L'Eden, où tous les objets sont initialement attribués, et la zone des survivants (divisée en de et vers) sont collectivement appelés la nouvelle génération.

Insérer la description de l'image ici

  1. Lorsqu'Eden n'a plus de mémoire, marquez les objets survivants d'Eden et de (actuellement aucun)

Insérer la description de l'image ici

  1. Utilisez l'algorithme de copie pour copier les objets survivants vers. Une fois la copie terminée, l'Eden et les souvenirs sont libérés.

Insérer la description de l'image ici

  1. Échanger de et vers

Insérer la description de l'image ici

  1. Après un certain temps, la mémoire d'Eden redevient insuffisante.

Insérer la description de l'image ici

  1. Marquez les objets survivants d'Eden et de

Insérer la description de l'image ici

  1. Copiez les objets survivants vers en utilisant l'algorithme de copie

Insérer la description de l'image ici

  1. Après la copie, Eden et la mémoire sont libérées

Insérer la description de l'image ici

  1. Échanger de et vers

Insérer la description de l'image ici

  1. Ancienne génération, lorsque l'objet de la zone survivant survit à plusieurs recyclages (jusqu'à 15 fois), il est promu à l'ancienne génération (une mémoire insuffisante dans la zone survivant ou des objets volumineux entraîneront une promotion précoce)

Échelle GC

  • Minor GCLa collecte des déchets se fait dans la nouvelle génération, avec des temps de pause courts
  • Mixed GCCollecte des déchets en pièces de nouvelle génération + ancienne génération, unique au collecteur G1
  • Full GCLa collecte complète des déchets de nouvelle génération + ancienne génération, les longs temps de pause, doivent être évités autant que possible

marquage tricolore

Autrement dit, trois couleurs sont utilisées pour enregistrer l'état de marquage de l'objet.

  • Noir – marqué
  • Gris – Marquage
  • Blanc – pas encore étiqueté
  1. Les trois premiers objets n'ont pas encore été traités et sont affichés en gris
effet de texte d'édition par défaut Android
  1. La référence de l'objet a été traitée et est affichée en noir. L'objet référencé en noir devient gris.
effet de texte d'édition par défaut Android
  1. Et ainsi de suite
effet de texte d'édition par défaut Android
  1. Marqué le long de la chaîne de référence
effet de texte d'édition par défaut Android
  1. Le dernier objet blanc non marqué est un déchet
effet de texte d'édition par défaut Android

Problème d'enchères manquantes simultanées

Les garbage collectors plus avancés prennent en charge le marquage simultané , c'est-à-dire que les threads utilisateur peuvent toujours fonctionner pendant le processus de marquage. Mais cela pose un nouveau problème : si le thread utilisateur modifie la référence de l'objet, il y aura alors un problème de marque manquante. Par exemple:

  1. Comme le montre la photo, les travaux de marquage ne sont pas encore terminés.
    effet de texte d'édition par défaut Android

  2. Le thread utilisateur travaille en même temps et déconnecte la référence entre les deux objets 3 et 4 de la première couche. À ce stade, pour le thread de garbage collection qui traite l'objet 3, il considérera l'objet 4 comme un déchet blanc.
    effet de texte d'édition par défaut Android

  3. Mais si d'autres threads utilisateur établissent des références aux objets 2 et 4, alors comme l'objet 2 est un objet traité en noir, le thread de garbage collection ne remarquera pas le changement dans la relation de référence, ce qui entraînera une marque manquée.
    effet de texte d'édition par défaut Android

  4. Si le fil utilisateur laisse l'objet noir faire référence à un nouvel objet, il y aura toujours un problème de marque manquante.
    effet de texte d'édition par défaut Android

Par conséquent, pour le marquage simultané , le problème du marquage manquant doit être résolu, c'est-à-direPour enregistrer les modifications pendant le processus de marquage. Il existe deux solutions :

  1. Incremental Update Méthode de mise à jour incrémentielle, le garbage collector du CMS utilise
    • L'idée est d'intercepter chaque action d'affectation. Tant que l'affectation se produit, l'objet attribué sera enregistré et confirmé à nouveau lors de la phase de re-marquage.
  2. Snapshot At The Beginning, SATBméthode d'instantané originale, le garbage collector G1 utilise
    • L'idée est d'intercepter chaque action d'affectation, mais les objets enregistrés sont différents et ces objets doivent être traités deux fois lors de l'étape de re-marquage.
    • Nouvel objetsera enregistré
    • L'objet dont la relation de référence a été suppriméeégalement enregistré

Éboueur -Parallel GC

  • Un GC mineur se produit lorsqu'Eden manque de mémoire. Il utilise un algorithme de copie marqué et doit suspendre le thread utilisateur.
  • Ancien : le GC complet se produit en raison d'une mémoire insuffisante. Un algorithme de marquage et de tri est utilisé et les threads utilisateur doivent être mis en pause.
  • Concentrez-vous sur le débit

Garbage Collector -ConcurrentMarkSweep GC (analyse simultanée des marques, avec fragmentation des déchets)

  • Il s'agit d'un collecteur qui fonctionne à l'ancienne époque, prend en charge le marquage simultané et utilise un algorithme de compensation simultanée.

    • Pas besoin de suspendre les threads utilisateur pendant le marquage simultané
    • Le fil de discussion utilisateur doit toujours être mis en pause lors du re-marquage
  • Si la concurrence échoue (c'est-à-dire que la vitesse de recyclage ne peut pas suivre la vitesse de création de nouveaux objets), le Full GC sera déclenché.

  • Concentrez-vous sur le temps de réponse

Garbage collector -G1 GC (collecteur par défaut du JDK)

  • Équilibrer le temps de réponse et le débit
  • Divisée en plusieurs zones, chaque zone peut servir d'éden, de survivant, d'ancien, d'énorme, parmi lesquelles l'énorme est spécialement préparé pour les gros objets.
  • Divisé en trois étapes : collecte nouvelle génération, marquage concurrent et collecte mixte
  • Si la concurrence échoue (c'est-à-dire que la vitesse de recyclage ne peut pas suivre la vitesse de création de nouveaux objets), le Full GC sera déclenché.

Etape de recyclage G1 - recyclage nouvelle génération

  1. Au départ, toutes les zones sont inutilisées
effet de texte d'édition par défaut Android
  1. Création de quelques objets et sélection de zones libres comme Eden Garden pour stocker ces objets
effet de texte d'édition par défaut Android
  1. Lorsqu'Eden a besoin d'un garbage collection, sélectionnez une zone libre comme zone survivante et utilisez l'algorithme de copie pour copier les objets survivants, ce qui nécessite de suspendre le thread utilisateur.
effet de texte d'édition par défaut Android
  1. La copie est terminée et la mémoire Eden précédente est libérée.
effet de texte d'édition par défaut Android
  1. Au fil du temps, le souvenir d’Eden devient insuffisant.
effet de texte d'édition par défaut Android
  1. Copiez les objets survivants d'Eden et de la zone de survivant précédente dans la nouvelle zone de survivant à l'aide d'un algorithme de copie, les objets plus anciens étant promus à l'ancienne génération.
effet de texte d'édition par défaut Android
  1. Libérez la mémoire d'Eden et de la zone de survivant précédente
effet de texte d'édition par défaut Android

Phase de collecte G1 - marquage simultané et collecte mixte

  1. Lorsque la mémoire occupée par l'ancienne génération dépasse le seuil, la marque concurrente est déclenchée et il n'est pas nécessaire de mettre le thread utilisateur en pause.
effet de texte d'édition par défaut Android
  1. Après le marquage simultané, il y aura une phase de re-marquage pour résoudre le problème de marquage manquant. À ce stade, le fil utilisateur doit être mis en pause. Une fois tout cela terminé, vous saurez quels objets survivants appartiennent à l’ancienne génération.

(Ensuite, la phase de collecte mixte entre. À ce stade, toutes les zones d'ancienne génération ne seront pas recyclées, mais les zones à haute valeur (moins d'objets survivants) seront recyclées en premier en fonction de l'objectif de temps de pause (c'est aussi l' origine du nommer Gabage Premier).)

effet de texte d'édition par défaut Android
  1. Dans la phase de collecte mixte, Eden, Survivant et Old sont impliqués dans la réplication. La figure suivante montre la réplication des objets survivants dans Eden et dans la zone des survivants.
effet de texte d'édition par défaut Android
  1. La figure suivante montre la réplication des objets survivants promus dans la zone ancienne génération et survivant.
effet de texte d'édition par défaut Android
  1. La copie est terminée et la mémoire est libérée. Entrer dans le prochain cycle de collecte de nouvelle génération, de marquage simultané et de collecte mixte
effet de texte d'édition par défaut Android

4.débordement de mémoire

Exiger

  • Être capable de nommer plusieurs situations typiques qui conduisent à un débordement de mémoire

Situations typiques [Question d'entretien : Dans quelles circonstances un débordement de mémoire se produira dans le projet et comment le résoudre]

  • Débordement de mémoire provoqué par une mauvaise utilisation du pool de threads

    • référenceday03.TestOomThreadPool
    • Utilisation abusive de pools de threads de taille fixe: Trop de tâches entraînent une saturation de la file d'attente du pool de threads, provoquant un débordement de mémoire ;
    • Utilisation abusive du pool de threads mis en mémoire tampon: Puisqu'il n'y a pas de limite supérieure sur le nombre de threads, le nombre de threads épuise les ressources système, provoquant un débordement de mémoire ;
    • Solution: N'utilisez pas Executorsla new FixedThreadPool()méthode intégrée avec pool de threads fixe et new CachedThreadPoll()la méthode avec pool de threads tampon intégré ; vous devez contrôler quelle file d'attente utiliser pour la file d'attente et définir vous-même la limite supérieure ;
  • Débordement de mémoire provoqué par l'interrogation de trop de données

    • référenceday03.TestOomTooManyObject
    • Interroger trop de données à la fois provoque un débordement de mémoire: Par exemple, sur une plateforme de commerce électronique, chaque fois qu'un utilisateur interroge, il y a toujours 1 million de produits. Si le volume total de données est de 363 Mo, les données seront extrêmement volumineuses lorsque plusieurs utilisateurs interrogeront et la mémoire du serveur sera épuisée. ;
    • Solution:Lors de l'interrogation de tout, vous pouvez ajouter des conditions de requête. Le plus important est de limitlimiter le nombre maximum d'enregistrements renvoyés. Ne renvoyez pas trop d'enregistrements dans une seule requête, sinon il est facile d'épuiser la mémoire du serveur ;
  • Débordement de mémoire provoqué par des classes générées dynamiquement

    • référenceday03.TestOomTooManyClass
    • Outil de génération dynamique de classes, faites attention à une utilisation correcte, pour éviter de générer trop de classes qui ne peuvent pas être publiées, conduisant à un épuisement de la mémoire métaespace ;
    • Insérer la description de l'image ici
    • Insérer la description de l'image ici

5.chargement de classe

Questions d'entretien :Processus de chargement de classeDélégation parentale
Exiger

  • maîtrephase de chargement de classe
  • Chargeurs de classe principale
  • comprendreMécanisme de délégation parentale

Trois étapes du processus de chargement de classe

  1. charger

    1. sera similaireZone de méthode de chargement du bytecode, et créerobjet classe.class(L'objet de classe est sur le tas)
    2. Si la classe parent de cette classe n'est pas chargée,Charger d'abord la classe parent
    3. Le chargement estexécution paresseuse(Le chargement ne sera déclenché que lorsque la classe sera utilisée)
  2. Lien

    1. vérifier-vérifierSi la classe est conforme aux spécifications de la classe, aux contrôles de légalité et de sécurité
    2. Préparer àLes variables statiques (statiques) allouent de l'espace et définissent des valeurs par défaut
    3. Analyse –Résoudre les références de symboles de pool constants en références directes
  3. initialisation

    1. mettre en œuvreBlocs de code statiques (y compris les variables statiques)etvariables statiques non finalesAffectation de
    2. statique finalmodifié基本类型L'affectation des variables est terminée pendant la phase de liaison
    3. l'initialisation estexécution paresseuse(Initialisé uniquement lorsqu'il est utilisé)

Moyens de vérification

  • Utilisez jps pour afficher le numéro de processus
  • Utilisez jhsdb pour déboguer et exécuter la commande jhsdb.exe hsdbpour ouvrir son interface graphique
    • Class BrowserVous pouvez vérifier quelles classes sont chargées dans le JVM actuel
    • Utilisez la commande console universepour afficher la plage de mémoire du tas
    • Utilisez la commande console g1regiondetailspour afficher regionles détails (région)
    • scanoops 起始地址 结束地址 对象类型Vous pouvez trouver l'adresse de l'objet dans une certaine plage en fonction du type
    • La inspect 地址commande console permet de visualiser les détails de l'objet correspondant à cette adresse.
  • Utilisez la commande javap pour afficher le bytecode de la classe

Description des codes

  • day03.loader.TestLazy- Le chargement des classes de vérification est paresseux et le chargement des classes n'est déclenché que lorsqu'elles sont utilisées.
  • day03.loader.TestFinal- Vérifiez que les variables modifiées avec final ne déclencheront pas le chargement de la classe

Chargeur de classe pour jdk 8

nom Quelle classe charger illustrer
Chargeur de classe Bootstrap(Démarrer le chargeur de classe JAVA_HOME/jre/lib Pas d'accès direct
Extension ClassLoader(chargeur de classe d'extension JAVA_HOME/jre/lib/ext Le niveau supérieur est Bootstrap, qui est affiché comme nul.
Chargeur de classe d'application(Chargeur de classe d'application chemin de classe Le supérieur est Extension
Chargeur de classe personnalisé Personnaliser Le parent est Application

Mécanisme de délégation parentale

soi-disantDélégation parentale, ce qui signifie que le chargeur de classe supérieure est prioritaire pour le chargement. Si le chargeur de classe supérieure

  • Cette classe peut être trouvée et chargée par le supérieur. Après le chargement, la classe est également visible par le chargeur de niveau inférieur.
  • Si cette classe est introuvable, le chargeur de classe de niveau inférieur est qualifié pour effectuer le chargement.

L’objectif de la délégation parentale est double

  1. Laissez les classes du chargeur de classes supérieur être partagées avec les subordonnés (et non l'inverse), afin que les classes puissent dépendre des classes principales fournies par jdk.
  2. Laissez le chargement des classes avoir la priorité et assurez-vous que les classes principales sont chargées en premier

Malentendus sur la délégation parentale

La réponse à la question d'entretien suivante est incorrecte

Insérer la description de l'image ici

Qu'est-ce qui ne va pas?

  • Puis-je charger un faux java.lang.System en écrivant mon propre chargeur de classe ? La réponse est non.

  • En supposant que votre propre chargeur de classe utilise la délégation parentale, le vrai java.lang.System sera chargé en premier par le chargeur de classe de démarrage , et le faux ne sera naturellement pas chargé.

  • En supposant que votre propre chargeur de classe n'utilise pas la délégation parentale, lorsque votre chargeur de classe charge le faux java.lang.System, il doit d'abord charger la classe parent java.lang.Object, mais vous n'utilisez pas de délégation et ne trouvez pas Java. .lang.Object donc le chargement échouera

  • Ce qui précède ne sont que des hypothèses . En fait, vous constaterez que lorsque le chargeur de classe personnalisé charge une classe commençant par java., il lèvera une exception de sécurité (il n'a pas à se charger car il y a un contrôle de sécurité). Dans les versions jdk9 et supérieures, ces packages spéciaux les noms sont liés au module. Après la liaison, il ne peut même pas être compilé.

Description des codes

  • day03.loader.TestJdk9ClassLoader - Démontre la relation de liaison entre les chargeurs de classe et les modules

6.Quatre types de références

Question d'entretien : Quels sont les types de types de référence d'objet ?

Exiger

  • Maîtriser les quatre types de citations

référence forte

  1. L'affectation de variable ordinaire est une référence forte, telle que A a = new A();
  2. Grâce à la chaîne de référence de GC Root,Si une référence forte ne parvient pas à trouver l'objet, l'objet peut être recyclé

Insérer la description de l'image ici

SoftRéférence

  1. Par exemple:SoftReference a = new SoftReference(new A());
  2. siLorsqu'il n'y a que des références logicielles à l'objet, l'objet ne sera pas recyclé pour le premier garbage collection . Si la mémoire est toujours insuffisante, l'objet ne sera libéré qu'après avoir été recyclé à nouveau.
  3. La référence logicielle elle-même doit être libérée conjointement avec la file d'attente de référence.
  4. Un exemple typique est celui des données de réflexion
    Insérer la description de l'image ici

FaibleRéférence

  1. Exemple : WeakReference a = new WeakReference(new A());
  2. Si seules des références faibles font référence à l’objet, celui-ci sera libéré à chaque fois que le garbage collection aura lieu.
  3. La référence faible elle-même doit être libérée avec la file d'attente de référence
  4. Un exemple typique est l'objet Entry dans ThreadLocalMap.

Insérer la description de l'image ici

Référence Phantom

  1. Exemple : PhantomReference a = new PhantomReference(new A(), referenceQueue);

  2. Il doit être utilisé conjointement avec la file d'attente de référence.Lorsque l'objet référencé par la référence virtuelle est recyclé, le thread Reference Handlermettra l'objet de référence virtuel en file d'attente, afin que vous puissiez savoir quels objets ont été recyclés et traiter davantage leurs ressources associées.

  3. Un exemple typique est Cleaner libérant la mémoire directe associée à DirectByteBuffer

Insérer la description de l'image ici

Description des codes

  • day03.reference.TestPhantomReference - démontre l'utilisation de base des références fantômes
  • day03.reference.TestWeakReference - simule ThreadLocalMap, utilise la file d'attente de référence pour libérer la mémoire d'entrée
package day03.reference;
// 前面讲的弱、虚引用配合引用队列,目的都是为了找到哪些 java 对象被回收,从而进行对它们关联的资源进行进一步清理
// 为了简化 api 难度,从 java 9 开始引入了 Cleaner 对象
public class TestCleaner1 {
    
    
    public static void main(String[] args) throws IOException {
    
    
        Cleaner cleaner = Cleaner.create();

        cleaner.register(new MyResource(), ()-> LoggerUtils.get().debug("clean 1")); //参数1关注的资源;参数2清理动作
        cleaner.register(new MyResource(), ()-> LoggerUtils.get().debug("clean 2"));
        cleaner.register(new MyResource(), ()-> LoggerUtils.get().debug("clean 3"));
        MyResource obj = new MyResource();  //局部变量;
        //下面的方法执行之前保持了强引用,则4不能被回收掉;
        cleaner.register(obj, ()-> LoggerUtils.get().debug("clean 4")); //4的清理动作不能被执行;
        cleaner.register(new MyResource(), ()-> LoggerUtils.get().debug("clean 5"));
        cleaner.register(new MyResource(), ()-> LoggerUtils.get().debug("clean 6"));

        System.gc();
        System.in.read(); //暂停的动作,因为cleaner是首部线程,当没有主线程执行时cleaner会自动结束,肉眼看不到效果;
    }

    static class MyResource {
    
    
    }
}

7.finaliser

Question d'entretien : Comprendre
les exigences pour finaliser

  • Maîtriser le principe de fonctionnement et les défauts de finalize

finaliser
[ Question d'entretien : Compréhension de finaliser ]

  • [Réponse générale] Il s'agit d'une méthode dans Object. Si une sous-classe la remplace, cette méthode sera appelée lors du garbage collection, et la libération et le nettoyage des ressources pourront y être effectués.
  • [ Excellente réponse ]Il est très mauvais de mettre la libération et le nettoyage des ressources dans la méthode finalize, ce qui affecte grandement les performances. Dans les cas graves, cela peut même provoquer un MOO (débordement de mémoire). Il a été marqué comme @Deprecated depuis Java9 et son utilisation n'est pas recommandée. .

Code d'essai :

package day03.reference;
public class TestFinalize {
    
    
    static class Dog {
    
    
        private String name;

        public Dog(String name) {
    
    
            this.name = name;
        }

        @Override
        protected void finalize() throws Throwable {
    
    
            LoggerUtils.get().debug("{}被干掉了?", this.name);
            int i = 1 / 0;
        }
    }

    public static void main(String[] args) throws IOException {
    
    
        new Dog("大傻");
        new Dog("二哈");
        new Dog("三笨");
        System.gc();
        System.in.read();
    }
    /*
    第一,从表面上我们能看出来 finalize 方法的调用次序并不能保证(那个对象先回收,就调用那个对象的finalize 方法)
    第二,日志中的 Finalizer 表示输出日志的线程名称,从这我们看出是这个叫做 Finalizer 的线程调用的 finalize 方法
    第三,你不能注释掉 `System.in.read()`,否则会发现(绝大概率)并不会有任何输出结果了;
         (因为finalize线程是一个守护线程,如果主线程没有了,守护线程就不执行行了),
         从这我们看出 finalize 中的代码并不能保证被执行
    第四,如果将 finalize 中的代码出现异常,会发现根本没有异常输出;(调用了try...catch方法)
    第五,还有个疑问,垃圾回收时就会立刻调用  finalize 方法吗?
         不会,先把对象加入到ReferenceQueue,从 ReferenceQueue 中逐一取出每个 Finalizer 对象,把它们从链表断开,并真正调用 finallize 方法
     */
}

Résultats du :
Insérer la description de l'image ici

finaliser le principe

  1. La logique de base du traitement de la méthode finalize se trouve dans la classe java.lang.ref.Finalizer, qui contient une variable statique (structure de liste doublement chaînée) nommée non finalisée. Finalizer peut également être considéré comme un autre objet de référence (statut et soft, Weak et faible sont équivalents, mais ils ne sont pas exposés au public et ne peuvent pas être utilisés directement)
  2. Lorsque l'objet avec la méthode finalize est remplacé, lorsque la méthode constructeur est appelée, la JVM le conditionnera dans un objet Finalizer et l'ajoutera à la liste chaînée non finalisée [À ce stade, la méthode finalize de l'objet dans la liste doublement chaînée n'a pas encore été appelé (lorsque le garbage collection aura lieu), il sera appelé)]

Insérer la description de l'image ici

  1. Il existe une autre variable statique importante dans la classe Finalizer, la file d'attente de référence ReferenceQueue, qui est vide au début. Lorsque les objets chien peuvent être récupérés, les objets Finalizer correspondant à ces objets chien seront ajoutés à cette file d'attente de référence.
  2. Mais pour le moment, l'objet Dog (l'objet associé à Finalizer) ne peut pas être recyclé immédiatement, car la chaîne de référence de non finalisé -> Finalizer le référence toujours. Pour le bien de [Ne soyez pas pressé de le recycler, attendez que j'aie fini d'ajuster la méthode finalize, puis Recyclage] ; en cas de recyclage, il n'y a aucun moyen d'appeler la méthode finalize de ces objets ;
  3. Le thread FinalizerThread supprimera chaque objet Finalizer un par un de ReferenceQueue, les déconnectera de la liste chaînée et appellera réellement la méthode finalize

Insérer la description de l'image ici

  1. Étant donné que l'intégralité de l'objet Finalizer a été déconnectée de la liste chaînée non finalisée, personne ne peut s'y référer ni à l'objet chien, il sera donc recyclé dans le prochain gc.

Inconvénients de finalize
[Pourquoi la méthode finalize est très mauvaise et affecte les performances]

très mauvais

  • La libération des ressources ne peut pas être garantie: FinalizerThread est un thread démon. Il est très probable que le thread se termine avant que le code n'ait le temps de terminer son exécution, ce qui entraînera une libération incorrecte des ressources.
  • Impossible de déterminer si une erreur s'est produite: Lors de l'exécution de la méthode finalize, toute exception (Throwable) sera avalée, de sorte qu'il ne soit pas possible de juger si une erreur s'est produite lors de la libération des ressources ;

Affecter les performances

  • La mémoire n'est pas libérée à temps: L'objet dont la méthode finalize est remplacée ne peut pas libérer la mémoire qu'il occupe au moment où il est gc pour la première fois, car il doit attendre que FinalizerThread appelle finalize et le supprime de la file d'attente non finalisée avant de pouvoir être véritablement gc'd. pour la deuxième fois, mémoire libre ;
  • On peut imaginer que gc est dû à une mémoire insuffisante et que l'appel de finalize est très lent (les opérations de suppression des deux files d'attente sont exécutées en série, et il ne devrait pas être rapide de libérer les ressources de la classe de connexion). être libéré à temps, et l'objet est libéré. ​​Si ce n'est pas le cas, il passera progressivement à l'ancienne génération. Trop d'accumulation de déchets dans l'ancienne génération conduira à un gc complet. Si la vitesse de libération après un gc complet ne peut toujours pas être maintenue avec la vitesse de création de nouveaux objets, un MOO se produira.

question

  • Certains articles mentionnent que [le thread Finalizer entrera en concurrence avec notre thread principal, mais comme il a une priorité inférieure et consomme moins de temps CPU, il ne rattrapera jamais le thread principal]. C'est évidemment faux. La priorité de FinalizerThread est plus élevée. que celui des threads ordinaires.La raison devrait être la lenteur de l'exécution en série de la finalisation et d'autres raisons (pas dues à une faible priorité)

Description des codes

  • day03.reference.TestFinalize - code de test pour finaliser

Je suppose que tu aimes

Origine blog.csdn.net/weixin_52223770/article/details/129006261
conseillé
Classement