Cet article présente principalement des informations pertinentes sur la zone mémoire Java et l'exception de dépassement de mémoire. Les amis qui en ont besoin peuvent se référer à
Zone mémoire Java et exception de dépassement de mémoire
Aperçu
Pour les développeurs de développement de programmes C et C, dans le domaine de la gestion de la mémoire, les programmeurs ont le droit absolu d'utiliser la mémoire, mais ils aussi L'essentiel est utiliser et nettoyer correctement la mémoire, ce qui nécessite un niveau élevé des programmeurs.
Pour les programmeurs Java, avec l'aide du mécanisme de gestion automatique de la mémoire de la machine virtuelle, il n'est pas nécessaire d'écrire du code supprimé/libéré pour chaque nouvelle opération, et il semble que ce soit un problème de fuite de mémoire ou de débordement de mémoire. que tout va bien avec la machine virtuelle gérant la mémoire. Cependant, c'est précisément parce que les programmeurs Java ont donné le pouvoir de contrôler la mémoire à la machine virtuelle Java. Une fois que des problèmes de fuites et de débordements de mémoire surviennent, si vous ne comprenez pas comment la machine virtuelle utilise la mémoire, le dépannage deviendra une tâche extrêmement difficile. travail.
Zone de données d'exécution Java
Nous pensons généralement que la JVM est composée de deux parties : le tas et la pile, mais la machine virtuelle Java réelle exécute des programmes Java dans le processus. , la mémoire qu'il gère est divisée en plusieurs zones de données différentes. Ces zones ont leurs propres objectifs, ainsi que l'heure de création et de destruction. Certaines zones existent au démarrage du processus de la machine virtuelle, et certaines zones sont créées et détruites en fonction du début et de la fin du thread utilisateur. Comme indiqué ci-dessous :
Compteur de programme
Si vous avez étudié les principes de la composition informatique, il devrait être clair que le programme Le compteur équivaut à une carte d'identité.De même, puisque la JVM possède également son propre CPU, lors de l'exécution d'un programme multithread, elle planifie l'exécution des threads en fonction du compteur du programme par rotation des tranches de temps.
Le registre du compteur de programmes est un petit espace mémoire. Sa fonction peut être considérée comme un indicateur de numéro de ligne du bytecode exécuté par le thread actuel. Dans le modèle conceptuel de la machine virtuelle (uniquement un modèle conceptuel, diverses machines virtuelles peuvent être implémentées de manière plus efficace), l'interpréteur de bytecode fonctionne en modifiant la valeur de ce compteur pour sélectionner l'étape suivante qui doit être exécutée. , les branches, les boucles, les sauts, la gestion des exceptions, la récupération de threads et d'autres fonctions de base doivent toutes s'appuyer sur ce compteur pour être exécutées.
Étant donné que le multithread de la machine virtuelle Java est implémenté en changeant de thread à tour de rôle et en allouant du temps d'exécution au processeur, à tout moment, un processeur (pour un processeur multicœur, un cœur) n'exécutera que instructions dans un seul fil. Par conséquent, afin de restaurer la position d'exécution correcte après le changement de thread, chaque thread doit disposer d'un compteur de programme indépendant. Les compteurs entre chaque thread ne s'influencent pas et sont stockés indépendamment. Nous appelons ce type de zone mémoire « thread privé ». . "mémoire.
Si le thread exécute une méthode Java, ce compteur enregistre l'adresse de l'instruction de bytecode de la machine virtuelle en cours d'exécution ; si le thread exécute une méthode Natvie, la valeur du compteur est vide (Non défini). Cette région de mémoire est la seule dans laquelle la spécification de machine virtuelle Java ne spécifie aucune condition OutOfMemoryError.
Pile de machines virtuelles Java
Comme le compteur de programme, les piles de machines virtuelles Java sont également privées de thread et leur cycle de vieIdentique au threading .
La pile de machines virtuelles décrit le modèle de mémoire d'exécution des méthodes Java : lorsque chaque méthode est exécutée, un cadre de pile (Stack Frame) est créé en même temps pour stocker les variables Tableaux, piles d'opérations, liens dynamiques, exportations de méthodes et autres informations. Le processus depuis chaque méthode appelée jusqu'à la fin de l'exécution correspond au processus de poussée d'un cadre de pile de la pile vers sa sortie de la pile dans la pile de la machine virtuelle.
Certaines personnes divisent souvent la mémoire Java en mémoire tas (Heap) et mémoire pile (Stack). Cette division est relativement grossière. La division des zones de mémoire Java est en réalité bien plus compliquée que cela. La popularité de cette méthode de division montre seulement que les zones de mémoire auxquelles la plupart des programmeurs accordent le plus d'attention et qui sont les plus étroitement liées à l'allocation de mémoire des objets sont ces deux zones. Le « tas » mentionné sera discuté spécifiquement plus tard, et la « pile » mentionnée est la pile de machines virtuelles dont nous parlons maintenant, ou la partie table de variables locales de la pile de machines virtuelles.La table de variables locales stocke divers types de données de base (booléen, byte, char, short, int, float, long, double), des références d'objet (type de référence, qui est n'est pas équivalent à l'objet lui-même. Selon les différentes implémentations de machine virtuelle, il peut s'agir d'un pointeur de référence pointant vers l'adresse de départ de l'objet, ou il peut pointer vers un handle représentant l'objet ou d'autres emplacements liés à cet objet) et le type returnAddress. (Montre l'adresse d'une instruction de bytecode).
Les données de 64 bits de long et de type double occuperont 2 espaces de variables locales (Slots), et les autres types de données n'en occuperont que 1. L'espace mémoire requis par la table des variables locales est alloué lors de la compilation. Lors de la saisie d'une méthode, il est entièrement déterminé la quantité d'espace variable locale que cette méthode doit allouer dans le cadre. La taille de la table des variables locales ne changera pas pendant l'exécution. de la méthode.
Dans la spécification de la machine virtuelle Java, deux conditions d'exception sont spécifiées pour cette zone : si la profondeur de pile demandée par le thread est supérieure à la profondeur autorisée par la machine virtuelle, une exception StackOverflowError sera levée si le la pile de machines virtuelles peut être étendue dynamiquement (la plupart des machines virtuelles Java actuelles peuvent être étendues dynamiquement, mais la spécification de machine virtuelle Java autorise également des piles de machines virtuelles de longueur fixe.) Lorsque l'expansion ne peut pas s'appliquer pour suffisamment de mémoire, une exception OutOfMemoryError sera levée.
Pile de méthodes natives
Les fonctions jouées par les piles de méthodes natives (Native Method Stacks) et les piles de machines virtuelles sont très similaires. La seule différence est que la pile de machines virtuelles. est La machine virtuelle exécute les services de méthode Java (c'est-à-dire le bytecode) et la pile de méthodes locale sert les méthodes natives utilisées par la machine virtuelle. La spécification de la machine virtuelle n'impose pas le langage, l'utilisation et la structure des données des méthodes dans la pile de méthodes locale, de sorte que des machines virtuelles spécifiques peuvent l'implémenter librement. Certaines machines virtuelles (telles que la machine virtuelle Sun HotSpot) combinent même directement la pile de méthodes locales et la pile de machines virtuelles en une seule. Comme la pile de machines virtuelles, la zone de pile de méthodes locale génère également des exceptions StackOverflowError et OutOfMemoryError.
Java Heap
Pour la plupart des applications, le Java Heap (Java Heap) est le plus grand morceau de mémoire géré par la machine virtuelle Java. Le tas Java est une zone mémoire partagée par tous les threads et est créée au démarrage de la machine virtuelle. Le seul objectif de cette zone mémoire est de stocker des instances d'objet, et presque toutes les instances d'objet allouent de la mémoire ici. Ceci est décrit dans la spécification de la machine virtuelle Java comme suit : Toutes les instances d'objets et tous les tableaux doivent être alloués sur le tas. Cependant, avec le développement des compilateurs JIT et la maturité progressive de la technologie d'analyse d'échappement, d'allocation sur la pile et de technologie d'optimisation de remplacement scalaire. will Cela entraînera des changements subtils, et tous les objets alloués sur le tas deviendront progressivement moins "absolus".
Le tas d'ava est la zone principale gérée par le ramasse-miettes, c'est pourquoi on l'appelle souvent le « tas GC (« Garbage Collected Heap, heureusement, il n'est pas traduit par « tas d'ordures » en Chine). Du point de vue du recyclage de la mémoire, étant donné que les collecteurs actuels utilisent essentiellement des algorithmes de collecte générationnelle, le tas Java peut également être subdivisé en : nouvelle génération et ancienne génération, les plus détaillées incluent l'espace Eden, l'espace From Survivor, To Survivor space, etc. Du point de vue de l'allocation de mémoire, le tas Java partagé par les threads peut être divisé en plusieurs tampons d'allocation privés par thread (Thread Local Allocation Buffer, TLAB). Cependant, quelle que soit la manière dont elle est divisée, cela n'a rien à voir avec le contenu du stockage. Quelle que soit la zone, les instances d'objet sont toujours stockées. Le but d'une division ultérieure est de mieux recycler la mémoire ou d'allouer de la mémoire plus rapidement. Dans ce chapitre, nous abordons uniquement le rôle de la zone mémoire. Les détails de l'allocation et du recyclage des zones ci-dessus dans le tas Java feront l'objet du prochain chapitre.
Selon la spécification de la machine virtuelle Java, le tas Java peut se trouver dans un espace mémoire physiquement discontinu, à condition qu'il soit logiquement continu, tout comme notre espace disque. Une fois implémenté, il peut être implémenté sous forme de taille fixe ou évolutif, mais les machines virtuelles grand public actuelles sont toutes implémentées de manière évolutive (contrôlées par -Xmx et -Xms). S'il n'y a pas de mémoire dans le tas pour terminer l'allocation d'instance et que le tas ne peut plus être étendu, une exception OutOfMemoryError sera levée.
Zone de méthode
La zone de méthode, comme le tas Java, est une zone mémoire partagée par chaque thread. Elle est utilisée pour stocker les classes qui ont été chargées par le virtuel. machine. Informations, constantes, variables statiques, code compilé par un compilateur juste à temps et d'autres données. Bien que la spécification de la machine virtuelle Java décrit la zone de méthode comme une partie logique du tas, elle possède un alias appelé Non-Heap (non-heap), qui doit être distingué du tas Java.
La spécification de la machine virtuelle Java a des restrictions très souples sur ce domaine. En plus de ne pas nécessiter de mémoire contiguë comme le tas Java et d'avoir l'option de taille fixe ou d'extensibilité, vous pouvez également choisir de ne pas implémenter le garbage collection. Relativement parlant, le comportement du garbage collection est relativement rare dans ce domaine, mais cela ne signifie pas que les données entrent dans la zone méthode et existent "de manière permanente" comme le nom de la génération permanente. L'objectif du recyclage de la mémoire dans ce domaine concerne principalement le recyclage des pools constants et le déchargement des types. D'une manière générale, les « scores » de recyclage de cette zone sont relativement insatisfaisants, notamment pour le déchargement des types. le Recyclage est en effet nécessaire.
Selon la spécification de la machine virtuelle Java, lorsque la zone de méthode ne peut pas répondre aux exigences d'allocation de mémoire, une exception OutOfMemoryError sera levée.
Pool de constantes d'exécution
Le pool de constantes d'exécution fait partie de la zone des méthodes. En plus des informations telles que la version de la classe, les champs, les méthodes, les interfaces et autres descriptions, le fichier Class contient également un pool de constantes (Constant Pool Table), qui est utilisé pour stocker divers littéraux générés lors de la compilation. et les références de symboles, qui seront stockées dans le pool de constantes d'exécution dans la zone de méthode après le chargement de la classe.
La machine virtuelle Java a des réglementations strictes sur le format de chaque partie du fichier Class (y compris naturellement le pool de constantes). Chaque octet doit être utilisé pour stocker le type de données qui doit être conforme aux exigences de la spécification. qui sera reconnu, chargé et exécuté par la machine virtuelle. Mais pour le pool de constantes d'exécution, la spécification de la machine virtuelle Java n'impose aucune exigence détaillée. Les machines virtuelles implémentées par différents fournisseurs peuvent implémenter cette zone de mémoire en fonction de leurs propres besoins. Cependant, de manière générale, en plus de sauvegarder les références de symboles décrites dans le fichier Class, les références directes traduites sont également stockées dans le pool de constantes d'exécution.
Une autre caractéristique importante du pool de constantes d'exécution par rapport au pool de constantes de fichier de classe est qu'il est dynamique. Le langage Java ne nécessite pas que les constantes soient générées uniquement lors de la compilation, c'est-à-dire qu'elles ne sont pas prédéfinies dans le fichier. Fichier de classe. Seul le contenu du pool peut entrer dans le pool de constantes d'exécution dans la zone des méthodes. De nouvelles constantes peuvent également être placées dans le pool pendant l'exécution. Cette fonctionnalité est souvent utilisée par les développeurs dans la fonction inn() de la String. méthode de classe.
Étant donné que le pool de constantes d'exécution fait partie de la zone de méthode, il sera naturellement limité par la mémoire de la zone de méthode. Lorsque le pool de constantes ne peut plus demander de mémoire, une exception OutOfMemoryError sera levée.
Mémoire directe
La mémoire directe (mémoire directe) ne fait pas partie de la zone de données d'exécution de la machine virtuelle, ni une zone de mémoire définie dans la spécification de la machine virtuelle Java , mais cette partie de la mémoire est également fréquemment utilisée et peut également provoquer des exceptions OutOfMemoryError.
La classe NIO (New Input/Output) a été ajoutée au JDK 1.4, et une méthode d'E/S basée sur les canaux et les tampons a été introduite. Elle peut utiliser directement la bibliothèque de fonctions natives Allouer de la mémoire hors tas. , puis opérer via un objet DirectByteBuffer stocké dans le tas Java comme référence à cette mémoire. Cela peut améliorer considérablement les performances dans certains scénarios, car cela évite de copier des données entre le tas Java et le tas natif.
Évidemment, l'allocation de mémoire directe locale ne sera pas limitée par la taille du tas Java. Cependant, puisqu'il s'agit de mémoire, elle sera certainement affectée par la taille de la mémoire locale totale (y compris la RAM et). Zone SWAP ou fichier d'échange) et processeur répondant aux limitations d'espace. Lorsque les administrateurs de serveur configurent les paramètres de la machine virtuelle, ils définissent généralement -Xmx et d'autres informations de paramètres en fonction de la mémoire réelle, mais ignorent souvent la mémoire directe, ce qui rend la somme de chaque zone de mémoire supérieure à la limite de mémoire physique (y compris les limites physiques et au niveau du système d'exploitation). ) ), entraînant une exception OutOfMemoryError lors de l'expansion dynamique.
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!