Modèle de mémoire de processeur
Le modèle de mémoire à cohérence séquentielle est un modèle de référence théorique. Le modèle de mémoire à cohérence séquentielle est généralement utilisé comme référence lors de la conception de modèles de mémoire JMM et de processeur. Le modèle de mémoire JMM et de processeur apportera quelques assouplissements au modèle de cohérence séquentielle lors de la conception, car si le processeur et JMM sont implémentés entièrement conformément au modèle de cohérence séquentielle, de nombreuses optimisations du processeur et du compilateur seront interdites, ce qui nuira aux performances d'exécution. aura un grand impact.
Selon l'assouplissement de l'ordre d'exécution des différents types de combinaisons d'opérations de lecture/écriture, les modèles de mémoire des processeurs courants peuvent être divisés dans les types suivants :
Détendez l'ordre des opérations d'écriture-lecture dans le programme, cela a abouti au modèle de mémoire de commande totale du magasin (TSO en abrégé).
Sur la base du précédent, nous avons continué à assouplir l'ordre des opérations d'écriture-écriture dans le programme, produisant ainsi le modèle de mémoire d'ordre de magasin partiel (appelé PSO).
Sur la base des versions 1 et 2 précédentes, nous avons continué à assouplir l'ordre des opérations de lecture-écriture et de lecture-lecture dans le programme, ce qui a abouti au modèle de mémoire assoupli de l'ordre de la mémoire (RMO en abrégé) et au modèle de mémoire PowerPC.
Notez que l'assouplissement des opérations de lecture/écriture par le processeur est ici basé sur le principe qu'il n'y a pas de dépendance de données entre les deux opérations (parce que le processeur doit se conformer à la sémantique comme si-série, le processeur ne Deux opérations de mémoire avec des dépendances de données seront réorganisées).
Le tableau suivant présente les caractéristiques détaillées des modèles de mémoire de processeur courants :
Nom du modèle de mémoire
Processeur correspondant
Réorganisation Store-Load
Réorganisation Store-Store
Load-Load et réorganisation Load-Store
Les écritures d'autres processeurs peuvent être lues plus tôt
Les écritures du processeur actuel peuvent être lues plus tôt
TSO
sparc-TSOX64
Y
Y
PSO
sparc-PSO
Y
Y
Y
RMO
ia64
Y
Y
Y
Y
PowerPC
PowerPC
Y
Y
Y
Y
Y
Dans ce tableau, nous pouvons voir toute la mémoire du processeur. Les modèles permettent tous la réorganisation en écriture-lecture pour la raison expliquée au chapitre 1. : ils utilisent tous des tampons d'écriture, ce qui peut entraîner une réorganisation des opérations d'écriture-lecture. Dans le même temps, nous pouvons voir que ces modèles de mémoire de processeur permettent des lectures et des écritures plus précoces sur le processeur actuel. La raison est également due à la zone de cache d'écriture : étant donné que la zone de cache d'écriture n'est visible que par le processeur actuel, cette fonctionnalité provoque. le processeur actuel pour pouvoir d'abord voir les écritures temporairement conservées dans leurs propres tampons d'écriture.
Les différents modèles de mémoire de processeur dans le tableau ci-dessus, de haut en bas, les modèles passent de fort à faible. Plus un processeur est axé sur les performances, plus le modèle de mémoire sera faible. Parce que ces processeurs souhaitent que le modèle de mémoire les contraigne le moins possible afin qu'ils puissent effectuer autant d'optimisations que possible pour améliorer les performances.
Étant donné que le modèle de mémoire du processeur commun est plus faible que JMM, lors de la génération du bytecode, le compilateur Java insérera des barrières de mémoire aux emplacements appropriés dans la séquence d'instructions d'exécution pour limiter la réorganisation du processeur. Dans le même temps, étant donné que les modèles de mémoire de différents processeurs ont des forces et des faiblesses différentes, afin de présenter un modèle de mémoire cohérent aux programmeurs sur différentes plates-formes de processeur, le nombre et les types de barrières de mémoire que JMM doit insérer dans différents processeurs varient également. . Pas pareil. La figure suivante montre un diagramme schématique des barrières de mémoire que JMM doit insérer dans différents modèles de mémoire de processeur :
Comme le montre la figure ci-dessus, JMM masque les différences entre les différents modèles de mémoire de processeur , qui présente aux programmeurs Java un modèle de mémoire cohérent sur différentes plates-formes de processeur.
JMM, la relation entre le modèle de mémoire du processeur et le modèle de mémoire à cohérence séquentielle
JMM est un modèle de mémoire au niveau du langage, et le modèle de mémoire du processeur est un modèle de mémoire au niveau matériel avec une cohérence séquentielle. Le modèle de mémoire sexuelle est un modèle théorique de référence. Ce qui suit est un diagramme comparant les forces et les faiblesses du modèle de mémoire de langage, du modèle de mémoire de processeur et du modèle de mémoire à cohérence séquentielle :
D'après la figure ci-dessus, nous pouvons voir que les quatre modèles de mémoire de processeur courants sont plus faibles que les trois modèles de mémoire de langage couramment utilisés. Le modèle de mémoire de processeur et le modèle de mémoire de langage sont tous deux plus faibles que le modèle de mémoire à cohérence séquentielle. Comme le modèle de mémoire du processeur, plus un langage recherche les performances d’exécution, plus la conception du modèle de mémoire sera faible.
Conception de JMM
Du point de vue d'un concepteur JMM, deux facteurs clés doivent être pris en compte lors de la conception d'un JMM :
L'utilisation du modèle de mémoire par le programmeur. Les programmeurs veulent des modèles de mémoire faciles à comprendre et à programmer. Les programmeurs souhaitent écrire du code basé sur un modèle de mémoire solide.
Implémentation du compilateur et du processeur du modèle de mémoire. Les compilateurs et les processeurs souhaitent que le modèle de mémoire les contraigne le moins possible afin de pouvoir effectuer autant d'optimisations que possible pour améliorer les performances. Les compilateurs et les processeurs souhaitent implémenter un modèle de mémoire faible.
Comme ces deux facteurs sont contradictoires, l'objectif principal du groupe d'experts JSR-133 lors de la conception de JMM est de trouver un bon point d'équilibre : d'une part, il doit fournir aux programmeurs une garantie de visibilité mémoire suffisamment forte D'un autre côté, les restrictions du compilateur et du processeur doivent être assouplies autant que possible. Voyons comment le JSR-133 atteint cet objectif.
Pour une explication spécifique, veuillez consulter l'exemple de code pour calculer l'aire d'un cercle mentionné précédemment :
double pi = 3.14; //A double r = 1.0; //B double area = pi * r * r; //C
L'exemple de code ci-dessus pour calculer l'aire d'un cercle a trois relations se produisent-avant :
A se produit - avant B ;
B se produit - avant C ;
A se produit - avant C
Puisque A se produit - avant B, la définition de se produit ; - avant nécessitera : L'exécution d'une opération. Le résultat de doit être visible par B, et l'ordre d'exécution de l'opération A doit être avant l'opération B. Cependant, du point de vue de la sémantique du programme, la réorganisation de A et B ne modifiera pas les résultats d'exécution du programme, mais peut également améliorer les performances d'exécution du programme (permettre cette réorganisation réduit les contraintes sur l'optimisation du compilateur et du processeur). En d’autres termes, parmi les trois relations ci-dessus, bien que 2 et 3 soient nécessaires, 1 est inutile. Par conséquent, JMM divise la réorganisation interdite par les exigences d'occurrence avant dans les deux catégories suivantes :
la réorganisation qui modifiera les résultats de l'exécution du programme.
La réorganisation ne modifiera pas les résultats de l'exécution du programme.
JMM adopte des stratégies différentes pour ces deux natures différentes de réorganisation :
Pour une réorganisation qui modifiera les résultats d'exécution du programme, JMM exige que le compilateur et le processeur interdisent une telle réorganisation.
JMM n'impose aucune exigence au compilateur et au processeur pour une réorganisation qui ne modifie pas les résultats d'exécution du programme (JMM autorise une telle réorganisation).
Ce qui suit est le schéma de conception de JMM :
Deux points peuvent être vus sur l'image ci-dessus :
Les règles qui se produisent avant fournies par JMM aux programmeurs Peut répondre aux besoins des programmeurs. Les règles d'occurrence avant de JMM sont non seulement simples et faciles à comprendre, mais fournissent également aux programmeurs des garanties de visibilité de la mémoire suffisamment solides (certaines garanties de visibilité de la mémoire n'existent pas nécessairement, comme A arrive avant B ci-dessus).
JMM a le moins de contraintes possible sur les compilateurs et les processeurs. De l'analyse ci-dessus, nous pouvons voir que JMM suit en fait un principe de base : tant que le résultat de l'exécution du programme ne change pas (en référence aux programmes monothread et aux programmes multithread correctement synchronisés), le compilateur et le processeur peuvent être optimisés, quelle que soit la manière dont ils sont optimisés. Par exemple, si le compilateur détermine après une analyse minutieuse qu'un verrou ne sera accessible que par un seul thread, le verrou peut être éliminé. Pour un autre exemple, si le compilateur détermine après une analyse minutieuse qu'une variable volatile ne sera accessible que par un seul thread, alors le compilateur peut traiter la variable volatile comme une variable ordinaire. Ces optimisations ne modifieront pas les résultats d'exécution du programme, mais amélioreront également l'efficacité d'exécution du programme.
Garantie de visibilité de la mémoire de JMM
La garantie de visibilité de la mémoire des programmes Java peut être divisée en trois catégories suivantes selon le type de programme :
Programmes monothread. Les programmes monothread n'ont pas de problèmes de visibilité de la mémoire. Le compilateur, le runtime et le processeur travaillent ensemble pour garantir que les résultats d'exécution d'un programme monothread sont les mêmes que les résultats d'exécution du programme dans le modèle de cohérence séquentielle.
Programmes multithread correctement synchronisés. L'exécution d'un programme multithread correctement synchronisé aura une cohérence séquentielle (les résultats de l'exécution du programme seront les mêmes que si le programme était exécuté dans un modèle de mémoire séquentiellement cohérent). C'est l'objectif de JMM, qui offre aux programmeurs des garanties de visibilité de la mémoire en limitant la réorganisation du compilateur et du processeur.
Programmes multithread non synchronisés/mal synchronisés. JMM leur apporte des garanties de sécurité minimales : la valeur lue lors de l'exécution d'un thread est soit la valeur écrite par un thread précédent, soit la valeur par défaut (0, null, false).
La figure suivante montre les similitudes et les différences dans les résultats d'exécution de ces trois types de programmes dans JMM et dans le modèle de mémoire cohérente séquentielle :
Tant que le programme multithread est correctement synchronisé, JMM garantit que les résultats d'exécution du programme sur n'importe quelle plate-forme de processeur sont cohérents avec les résultats d'exécution du programme dans le modèle de mémoire séquentiellement cohérent.
Les correctifs de JSR-133 sur l'ancien modèle de mémoire
Les correctifs de JSR-133 sur l'ancien modèle de mémoire avant JDK5 en incluent principalement deux :
Améliorer la sémantique de la mémoire volatile. L'ancien modèle de mémoire permettait de réorganiser les variables volatiles avec des variables ordinaires. JSR-133 limite strictement la réorganisation des variables volatiles et des variables ordinaires, de sorte que l'écriture-lecture volatile et l'acquisition de libération de verrouillage aient la même sémantique de mémoire.
Améliorez la sémantique de la mémoire de final. Dans l'ancien modèle de mémoire, la valeur de la même variable finale lue plusieurs fois peut être différente. À cette fin, JSR-133 ajoute deux règles de réorganisation pour la finale. Final a désormais une sécurité d'initialisation.
Ce qui précède est l'analyse approfondie du modèle de mémoire Java : résumé Pour plus de contenu connexe, veuillez faire attention au site Web PHP chinois (www.php.cn) !