Maison >Java >javaDidacticiel >Explication du cas Espace mémoire JVM (collection recommandée)
Aujourd'hui, parlons avec vous du sujet de l'espace mémoire JVM. C'est aussi une question souvent posée lors des entretiens dans les sociétés Internet de premier plan. Il est recommandé aux amis de la collecter et de la lire souvent, en se concentrant sur la compréhension. Bon, ne parlons plus, passons au sujet principal aujourd'hui.
La JVM divisera la mémoire en différentes zones de données, alors où sont allouées les classes chargées ?
L'image ci-dessous montre différentes zones de mémoire, notamment : la zone de méthode, le tas, la pile de machine virtuelle, la pile de méthodes locale et le compteur de programme.
La zone de méthode est utilisée pour stocker des données telles que des informations de classe, des constantes, des variables statiques, du code compilé par le compilateur juste à temps, etc. qui ont été chargées par la machine virtuelle. Les cinq étapes de chargement de classe sont mentionnées dans Class Loading. Dans la phase de chargement, la structure de stockage statique représentée par le flux d'octets sera convertie en structure de données d'exécution de la zone méthode. Dans la phase de préparation, toute la mémoire utilisée par les variables sera allouée dans la zone méthode.
Allez sur un code simple, calculez (1+2)*3 et retournez
public int cal() { int a = 1; int b = 2; int c = 3; return (a + b) * c; }
Lorsque ce code est chargé dans la machine virtuelle, il devient les octets suivants Lorsque la machine virtuelle exécute le code, il sera exécuté ligne par ligne.
Java est multithread Une fois que le thread revient, il doit savoir où se trouve la position d'exécution d'origine. Le compteur du programme permet d'enregistrer cette position d'exécution. Afin de garantir que les compteurs entre les threads ne s'influencent pas, cette zone mémoire est privée au thread.
虚拟机栈也是线程私有的,生命周期与线程相同。每个线程都有自己的虚拟机栈,如果这个线程执行了一个方法,就会创建一个栈帧,方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。比如下面的例子,fun1调用fun2,fun2调用fun3,fun3创建Hello对象。
public void fun1() { fun2(); } public void fun2() { fun3(); } public void fun3() { Hello hello = new Hello(); }
调用的时候,流程图如下:
执行完成的时候,流程图如下:
每一个栈帧都包括了局部变量表、操作数栈、动态连接、方法返回地址和一些额外的附加信息。局部变量主要是存放方法参数以及方法内部定义的局部变量,操作数栈是一个后入先出栈,当方法刚刚开始执行的时候,这个方法的操作数栈是空的,在方法的执行过程中,会有各种字节码指令往操作数栈中写入和提取内容,也就是出栈/入栈操作。
我们通过上面(1+2)*3的例子,把方法区、程序计数器、虚拟机栈的协同工作理一下。首先通过javap查看它的字节码,经过类加载器加载后,此时这个字节码存在方法区中。stack表示栈深度是2,locals是本地变量的slot个数,args_size是入参的个数,默认是this。栈的深度、本地变量个数,入参个数,都是在编译器决定的。
如下图,指令的位置是方法区,局部变量和操作数栈的位置是虚拟机栈,程序计数器就在程序计数器(这个下面的图就不再重复)。当执行偏地址为0的指令的时候,程序计数器为0,局部变量第一个值是this,当前的指令就是方法区0:iconst_1
,指令iconst_1就是把int常量值1进栈,这个1就到了虚拟机栈的操作数栈中。
当执行偏地址为1的指令的时候,程序计数器为1,把操作数栈的值赋值到局部变量,此时操作数栈清空了,局部变量多了一个1,这条指令执行完,就是对应上面int a=1的语句。
De plus, les affectations des deux énoncés b et c correspondent aux instructions 2, 3, 4 et 5, qui ne seront pas répétées ici. Après avoir exécuté 5, comme le montre la figure ci-dessous :
Lors de l'exécution de 6, iload_1 est exécuté, ce qui consiste à placer la deuxième variable locale de type int en haut de la pile. La variable ici est 1.
Lors de l'exécution de 7, iload_2 est exécuté, ce qui signifie placer la troisième variable locale de type int en haut de la pile. La variable ici est 2.
Lors de l'exécution de 8, il s'agit de l'instruction iadd, ce qui signifie que les deux éléments de type int en haut de la pile sont retirés de la pile, puis poussés vers le haut de la pile une fois le résultat obtenu. obtenu.
Lors de l'exécution de 9, affectez l'élément 3 en haut de la pile à la cinquième variable locale.
Lorsque l'exécution atteint 11, la valeur de la cinquième variable locale est poussée en haut de la pile. Lorsque l'exécution atteint 13, la valeur de la quatrième variable locale est poussée en haut de la pile. 14, les deux valeurs en haut de la pile sont poussées. Un élément de type int est retiré de la pile et le résultat multiplié est poussé sur la pile. Lorsque 15 est exécuté, l'élément de type int en haut de la pile. la pile actuelle est renvoyée par la méthode actuelle. Ce sont presque les mêmes que ceux ci-dessus, je n’entrerai donc pas dans les détails.
Le seul objectif de la zone de mémoire tas est de stocker les instances d'objet, et presque toutes les instances d'objet allouent de la mémoire ici. Par exemple, fun1 ci-dessus appelle fun2, fun2 appelle fun3 et fun3 crée un objet Hello. Lorsque l'objet est créé dans la méthode fun3, il est créé dans le tas et l'adresse est affectée à la variable locale de fun3. Le tas Java peut également être subdivisé en : nouvelle génération et ancienne génération ; la nouvelle génération est également subdivisée en espace Eden, espace From Survivor et To Survivor.
Le processus global est le suivant : Tout d'abord, compilez le fichier Java dans un fichier de classe et chargez-le dans la zone de méthode via le chargeur de classe. Lorsqu'un thread appelle une méthode, il créera un cadre de pile, lira le bytecode dans la zone de méthode et exécutera l'instruction. Lorsque l'instruction est exécutée, la position d'exécution sera enregistrée dans le compteur du programme. sera créé dans la mémoire tas. Une fois la méthode exécutée, le cadre de pile sera sauté.
-XX : PermSize : Capacité mémoire de génération permanente.
-XX:MaxPermSize : Capacité mémoire maximale de la génération permanente.
-XX:MetaspaceSize : La taille de la valeur initiale du métaespace
-XX:MaxMetaspaceSize : La taille maximale du métaespace
-XX:CompressedClassSpaceSize : La taille de l'espace pour stocker la partie métadonnées de la classe Klass dans le métaespace
-Xss : Capacité de la mémoire de la pile.
-Xms : Capacité de mémoire tas.
-Xmx : La capacité de mémoire maximale du tas, généralement la même que le paramètre -Xms, pour éviter l'impact de l'expansion du runtime.
-Xmn : Capacité mémoire nouvelle génération, l'ancienne génération est la capacité mémoire tas - capacité mémoire nouvelle génération
-XX : SurvivorRatio=8 : La nouvelle génération est également subdivisée en espace Eden, Espace From Survivor et Espace To Survivor , défini sur 8 Représente l'espace Eden : De l'espace Survivant : À l'espace Survivant = 8:1:1 Par exemple, si la nouvelle génération a 10M, alors l'espace Eden occupe 8M, et l'espace From Survivor et l'espace To Survivor occupent chacun 1M.
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!