Maison  >  Article  >  Java  >  Introduction aux bases de la JVM : zone de données d'exécution

Introduction aux bases de la JVM : zone de données d'exécution

巴扎黑
巴扎黑original
2017-07-21 16:46:33884parcourir

Je pense que cette image devrait être familière à tous ceux qui ont des contacts avec JVM On peut dire que c'est . JVMLa première leçon de démarrage. Parmi eux, "heap" et "pile de machines virtuelles (stack) est encore plus familier. Ce qui suit donnera une brève introduction à la zone de données d'exécution de JVM basée sur cette image.

Compteur de programme (Registre du compteur de programme)

C'est la même chose comme opération informatique Le compteur de programme dans le système est similaire. Dans le système d'exploitation informatique, le compteur de programme représente l'adresse de la prochaine instruction à exécuter par ce processus. Pour JVM, le compteur de programme. peut être considérée comme l'adresse exécutée par le thread actuel. L'indicateur de numéro de ligne de bytecode, chaque thread a un compteur de programme (c'est facile à comprendre, chaque thread exécute des tâches, si le thread est commuté, il doit pouvoir être restauré. à la bonne position), le point important est ——Program Counter, c'est le seul dans la spécification JVM qui ne précise pas que cela provoquera une zone OutOfMemory (fuite de mémoire, ci-après dénommée MOO) . En d'autres termes, les 4 zones restantes dans l'image ci-dessus peuvent provoquer MOO.

☆Piles de machines virtuelles (piles de machines virtuelles Java)

Cette zone mémoire est ce que nous avons souvent Quand on parle de "pile " , ce qu'on sait bien c'est qu'elle sert à stocker des variables, c'est-à-dire par exemple :

int i = 0;

La mémoire de la pile de machine virtuelle utilisera 4 octets pour stocker le i variables. L'espace mémoire pour les variables peut être déterminé dès le début (pour les variables de référence, bien sûr, il stocke une référence d'adresse, et sa taille est également fixe), donc cette zone mémoire peut être déterminée par le compilateur. Cette zone peut lancer StackOverflowError ou OOM erreur. Définissez les paramètres JVM "-Xss228k" (la taille de la pile est 228k).

 1 package com.jvm; 2  3 /** 4  * -Xss228k,虚拟机栈大小为228k 5  * Created by yulinfeng on 7/11/17. 6  */ 7 public class Test { 8     private static int count = 0; 9 10     public static void main(String[] args) {11         Test test = new Test();12         test.test();13     }14 15     /**16      * 递归调用17      */18     private void test() {19         try {20             count++;21             test();22         } catch (Throwable e) {     //Exception已经捕获不了JVM抛出的StackOverflowError23             System.out.println("递归调用次数" + count);24             e.printStackTrace();25         }26     }27 }

Il s'agit d'une récursion sans conditions de terminaison. Le résultat de l'exécution est comme indiqué dans la figure ci-dessous JVM lance StackOverflowError indique la profondeur de la pile. demandé par le fil de discussion Supérieur à la profondeur autorisée par JVM.

Pour les situations à thread unique, StackOverflowError est quand même lancé. Si une exception OOM est levée, la cause est que des threads sont créés en continu jusqu'à ce que la mémoire soit épuisée.

La mémoire de la JVM se compose de la mémoire du tas + mémoire de la zone de méthode + restante mémoire, C'est-à-dire la mémoire restante =La mémoire allouée par le système d'exploitation à la JVM - mémoire tas - mémoire de la zone de méthode. -Xss définit la capacité de pile de chaque thread, c'est-à-dire le nombre de threads pouvant être créés = mémoire restante / Mémoire de pile. À ce stade, si la mémoire de la pile est plus grande, le nombre de threads pouvant être créés sera plus petit, et MOO se produira facilement si la mémoire de la pile est plus petite, le nombre ; de fils de discussion pouvant être créés sera plus grand, et ce ne sera pas facile MOO apparaît.

La meilleure façon d'éviter cette situation est de réduire la mémoire du tas + mémoire de la zone de méthode, ou de réduire de manière appropriée la mémoire de la pile. Pour la configuration de la mémoire de la pile, utilisez généralement la valeur par défaut 1M, ou utilisez le système d'exploitation 64 bits et 64 morceaux de JVM.

Pile de méthodes natives (Pile de méthodes natives)

Pile de méthodes natives Semblable à la pile de machines virtuelles, la différence est que la pile de machines virtuelles sert la méthode Java, tandis que la pile de méthodes locales sert la méthode Native . Dans l'implémentation de la machine virtuelle HotSpot, la pile de méthodes locales et la pile de machine virtuelle sont combinées en une seule. De même, cela lancera également StackOverflowError <.> et MOO exceptions.

Tas Java

  对于堆,Java程序员都知道对象实例以及数组内存都要在堆上分配。堆不再被线程所独有而是共享的一块区域,它的确是用来存放对象实例,也是垃圾回收GC的主要区域。实际上它还能细分为:新生代(Young Generation)、老年代(Old Generation)。对于新生代又分为Eden空间、From Survivor空间、To Survivor空间。至于为什么这么分,这涉及JVM的垃圾回收机制,在这里不做叙述。堆同样会抛出OOM异常,下面例子设置JVM参数” -Xms20M -Xmx20M(前者表示初始堆大小20M,后者表示最大堆大小20M)。

 1 package com.jvm; 2  3 import java.util.ArrayList; 4 import java.util.List; 5  6 /** 7  * -Xms20M -Xmx20M 堆初始大小20M 堆最大大小20M 8  * Created by yulinfeng on 7/11/17. 9  */10 public class Test {11 12     public static void main(String[] args) {13         List<Test> list = new ArrayList<Test>();14         int count = 0;15         try {16             while (true) {17                 count++;18                 list.add(new Test());   //不断创建线程19             }20         } catch (Throwable e) {21             System.out.println("创建实例个数:" + count);22             e.printStackTrace();23         }24 25     }26 }

  执行的结果可以清楚地看到堆上的内存空间溢出了。

方法区(Method Area

  对于JVM的方法区,可能听得最多的是另外一个说法——永久代(Permanent Generation),呼应堆的新生代和老年代。方法区和堆的划分是JVM规范的定义,而不同虚拟机有不同实现,对于Hotspot虚拟机来说,将方法区纳入GC管理范围,这样就不必单独管理方法区的内存,所以就有了永久代这么一说。方法区和操作系统进程的正文段(Text Segment)的作用非常类似,它存储的是已被虚拟机加载的类信息、常量(从JDK7开始已经移至堆内存中)、静态变量等数据。现设置JVM参数为-XX:MaxPermSize=20M(方法区最大内存为20M)。

 1 package com.jvm; 2  3 import java.util.ArrayList; 4 import java.util.List; 5  6 /** 7  * -XX:MaxPermSize=20M 方法区最大大小20M 8  * Created by yulinfeng on 7/11/17. 9  */10 public class Test {11 12     public static void main(String[] args) {13         List<String> list = new ArrayList<String>();14         int i = 0;15         while (true) {16             list.add(String.valueOf(i++).intern());   //不断创建线程17         }18     }19 }

 En fait, pour le code ci-dessus, les résultats de l'exécution sur JDK6, JDK7, JDK8 Tous sont différents. La raison en est que le pool de constantes de chaîne est toujours stocké dans la zone de méthode (génération permanente) dans JDK6, il lancera donc OutOfMemoryError:Permanent Space  ; et après JDK7, le pool de constantes de chaîne a été déplacé vers le tas Java, et le code ci-dessus ne sera pas lancez OOM, si la mémoire du tas est modifiée en 20M, il lancera OutOfMemoryError:Java tas space ; Quant au JDK8, la notion de zone de méthode a été complètement annulée et remplacée par métaespace ( Metaspace)", donc dans JDK8 paramètres de la machine virtuelle "-XX:MaxPermSize" n'a aucune signification. Il est remplacé par "-XX:MetaspaceSize" et " -XX. :MaxMetaspaceSize” etc.

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!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn