Maison  >  Article  >  Java  >  Qu'est-ce qu'un tas ? Quel est le domaine de la méthode ? Introduction à la zone de tas et de méthode dans le modèle de mémoire JVM

Qu'est-ce qu'un tas ? Quel est le domaine de la méthode ? Introduction à la zone de tas et de méthode dans le modèle de mémoire JVM

不言
不言original
2018-09-15 17:43:0411941parcourir

Le contenu de cet article porte sur ce qu'est un tas ? Quel est le domaine de la méthode ? L'introduction de la zone de tas et de méthodes dans le modèle de mémoire JVM a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer, j'espère que cela vous sera utile.

1. Tas

1.1. Qu'est-ce qu'un tas

Le tas est une zone mémoire utilisée pour stocker des objets. C’est donc la cible principale de la gestion du garbage collector (GC). Il présente les caractéristiques suivantes :

  • Le tas est logiquement divisé en « nouvelle génération » et « ancienne génération ». Étant donné que la plupart des objets de JAVA sont nés et détruits et qu'un petit nombre peut rester longtemps en mémoire, afin d'obtenir le recyclage le plus efficace de ces deux objets, le tas est divisé en nouvelle génération et ancienne. génération, et la stratégie de recyclage est différente. Différents éboueurs ont des mécanismes de recyclage différents pour ces deux zones logiques, que nous expliquerons en détail dans les chapitres suivants.

  • La mémoire occupée par le tas ne nécessite pas de continuité physique, seulement une continuité logique.

  • Le tas est généralement implémenté comme une taille de mémoire extensible. Utilisez "-Xms" et "-Xmx" pour contrôler la mémoire minimale et maximale du tas, et l'action d'expansion est effectuée. par la machine virtuelle. Cependant, comme ce comportement consomme des performances, les mémoires maximale et minimale du tas sont généralement définies pour être égales.

  • Le tas est une zone mémoire partagée par tous les threads, donc chaque thread peut récupérer le même objet sur le tas.

  • Le cycle de vie du tas est créé au démarrage de la machine virtuelle.

1.2. Exception du tas

Lorsque le tas ne peut pas allouer de mémoire objet et ne peut plus être étendu, une exception OutOfMemoryError sera jeté.

De manière générale, un GC sera effectué lorsque le tas ne peut pas allouer d'objets. Si l'objet ne peut toujours pas être alloué après GC, une erreur d'épuisement de la mémoire sera signalée. Cette situation peut être simulée en générant continuellement de nouveaux objets sans libérer de références :

/**
 * java堆溢出demo
 * JVM参数:-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError
 * Created by chenjunyi on 2018/4/25.
 */
public class HeapOOM {

    static class OOMObject {
    }

    public static void main(String[] args) {
        List<OOMObject> list = new ArrayList<>();
        //不断创建新对象,使得Heap溢出
        while (true) {
            list.add(new OOMObject());
        }
    }

}

Dans le code ci-dessus, les objets sont créés en continu sans libérer de références, ce qui empêche le GC de récupérer la mémoire du tas. Final OutOfMemoryError, message d'erreur :

java.lang.OutOfMemoryError: Java heap space

2. Zone de méthode

2.1 Qu'est-ce que la zone de méthode

Zone de méthode, également appelée non-Heap ? (Non-Heap) est une autre zone de mémoire partagée par les threads. Il stocke principalement le bytecode de classe chargé, la classe/méthode/champ et autres objets de métadonnées, les constantes statiques finales, les variables statiques, le code compilé par le compilateur JIT et d'autres données. De plus, la zone de méthode contient une zone spéciale "pool de constantes d'exécution", leur relation est illustrée dans la figure ci-dessous :

(1) Bytecode de classe chargé : Pour utiliser une classe, son bytecode doit d'abord être chargé dans la mémoire de la JVM. Quant à la source du bytecode de classe, elle peut être diverse, comme les fichiers .class, la transmission réseau ou directement générée par le framework de bytecode cglib.
(2) Objets de métadonnées tels que classe/méthode/champ : une fois le bytecode chargé, la JVM générera Classe/Méthode/Champ et d'autres objets pour cette classe en fonction du contenu. généralement dans Il est souvent utilisé en réflexion. Contrairement aux objets d'instance Java stockés dans le tas, ces deux objets sont stockés dans la zone de méthode.
(3) constantes statiques finales et variables statiques : pour ces deux types de membres de classe, la JVM créera une copie des données pour eux dans la zone de méthode, il n'y a donc qu'une seule copie des membres de classe modifiés statiquement de la même classe ;
(4) Résultats de la compilation du compilateur JIT : en prenant la machine virtuelle hotspot comme exemple, elle utilisera le compilateur juste à temps JIT pour optimiser le code du hotspot pendant l'exécution. compilez le bytecode en code machine. Normalement, la JVM utilise la méthode « interprétation et exécution » pour exécuter le bytecode. Autrement dit, lorsque la JVM lit une instruction de bytecode, elle effectuera des opérations de pile selon des règles prédéterminées, et les opérations de pile seront ensuite mappées sur l'opération sous-jacente de la machine. ; après la compilation JIT, le code machine exécuté traitera directement avec la machine sous-jacente. Comme le montre la figure ci-dessous :

2.2 Pool constant d'exécution

Dans la section 2.1, nous avons découvert les classes. Le bytecode sera analysé lors du chargement et différentes choses seront générées et stockées dans la zone de méthode. Le bytecode d'une classe contient non seulement des informations de description telles que la version de la classe, les champs, les méthodes, les interfaces, etc., mais contient également un pool de constantes. Le pool de constantes est utilisé pour stocker tous les littéraux et références de symboles (tels que les littéraux de chaîne) utilisés dans le bytecode. Lorsque la classe est chargée, ils entrent dans le pool de constantes d'exécution dans la zone de méthode pour le stockage.

Le pool de constantes d'exécution est une partie spéciale de la zone des méthodes et est dynamique, c'est-à-dire qu'en plus d'y écrire le pool de constantes lorsque la classe est chargée, des constantes peuvent également y être écrites pendant. le fonctionnement du programme Java. :

1 //使用StringBuilder在堆上创建字符串abc,再使用intern将其放入运行时常量池
2 String str = new StringBuilder("abc");
3 str.intern();
4 //直接使用字符串字面量xyz,其被放入运行时常量池
5 String str2 = "xyz";

2.3. Implémentation de la zone méthode

L'implémentation de la zone méthode n'est pas clairement stipulée dans la spécification de la machine virtuelle. Il existe actuellement deux implémentations principales. méthodes :

(1)HotSpot虚拟机1.7-:在JDK1.6及之前版本,HotSpot使用“永久代(permanent generation)”的概念作为实现,即将GC分代收集扩展至方法区。这种实现比较偷懒,可以不必为方法区编写专门的内存管理,但带来的后果是容易碰到内存溢出的问题(因为永久代有-XX:MaxPermSize的上限)。在JDK1.7+之后,HotSpot逐渐改变方法区的实现方式,如1.7版本移除了方法区中的字符串常量池。

(2)HotSpot虚拟机1.8+:1.8版本中移除了方法区并使用metaspace(元数据空间)作为替代实现。metaspace占用系统内存,也就是说,只要不碰触到系统内存上限,方法区会有足够的内存空间。但这不意味着我们不对方法区进行限制,如果方法区无限膨胀,最终会导致系统崩溃。

  我们思考一个问题,为什么使用“永久代”并将GC分代收集扩展至方法区这种实现方式不好,会导致OOM?首先要明白方法区的内存回收目标是什么,方法区存储了类的元数据信息和各种常量,它的内存回收目标理应当是对这些类型的卸载和常量的回收。但由于这些数据被类的实例引用,卸载条件变得复杂且严格,回收不当会导致堆中的类实例失去元数据信息和常量信息。因此,回收方法区内存不是一件简单高效的事情,往往GC在做无用功。另外随着应用规模的变大,各种框架的引入,尤其是使用了字节码生成技术的框架,会导致方法区内存占用越来越大,最终OOM。

2.4.方法区异常

  在2.3一节中,我们了解到方法区的2种实现方式最终都会有一个最大值上限,因此若方法区(含运行时常量池)占用内存到达其最大值,且无法再申请到内存时,便会抛出OutOfMemoryError。

  在下面的例子中,我们将使用cglib字节码生成框架不断生成新的类,最终使方法区内存占用满,抛出OutOfMemoryError:

/**
 * java方法区溢出OutOfMemoryError(JVM参数适用于JDK1.6之前,借助CGLIB)
 * JVM参数:-XX:PermSize=10M -XX:MaxPermSize=10M
 * Created by chenjunyi on 2018/4/26.
 */
public class JavaMethodAreaOOM {

    public static void main(String[] args) {
        while (true) {
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(OOMObject.class);
            enhancer.setUseCache(false);
            enhancer.setCallback((MethodInterceptor) (o, method, objects, methodProxy) -> methodProxy.invokeSuper(objects, args));
            enhancer.create();
        }
    }

    static class OOMObject {
    }

}

报错信息为:

1 Caused by: java.lang.OutOfMemoryError: PermGen space
2   at java.lang.ClassLoader.defineClass1(Native Method)
3   ···

其实,在日常开发中,不仅仅使CGlib字节码生成框架会产生大量的class信息,动态语言、JSP、基于OSGI的应用都会在方法区额外产生大量的类信息。

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