Explication détaillée de la gestion de la mémoire PHP

小云云
Libérer: 2023-03-21 06:20:01
original
2401 Les gens l'ont consulté

En C, malloc et free sont utilisés directement pour allouer et libérer de la mémoire. Cependant, l'allocation et la libération fréquentes de mémoire entraîneront une fragmentation de la mémoire et réduiront les performances du système. Les variables PHP seront allouées et libérées très fréquemment. Une allocation de cette manière entraînera de sérieux problèmes de performances. En tant qu'application au niveau du langage, cette perte n'est pas acceptable, c'est pourquoi PHP a implémenté son propre pool de mémoire ZendMM pour remplacer le malloc de la glibc et résoudre gratuitement le problème de l'allocation de mémoire fréquente. libérer.
Il définit les opérations de mémoire selon trois granularités : bloc, page et emplacement. La taille de chaque bloc est de 2 Mo et chaque page est de 4 Ko. Un bloc est découpé en 512 pages et chaque page est découpée en plusieurs emplacements à appliquer. pour la mémoire. Différentes stratégies d'allocation sont mises en œuvre selon la taille de l'application
énorme : supérieure à 2Mo, appeler directement l'allocation système, allouer plusieurs morceaux
grande : demander une mémoire supérieure à 3092B (3/4page), moins de 2044 Ko (511 pages) d'allocation Plusieurs pages
petites : La mémoire de l'application est inférieure à 3092 Mo Le pool de mémoire a défini 30 tailles de mémoire différentes (8, 16, 32..., 3072) à l'avance. sur différentes pages Lors de la demande de mémoire, vous pouvez directement trouver l'emplacement correspondant sur la mémoire correspondante. Le pool de mémoire stocke les informations principales du pool de mémoire via la structure zend_mm_heap, telles que la liste chaînée de grande mémoire, la liste chaînée de morceaux, la liste chaînée de blocs. liste de chaque taille de slot, etc.
La grande mémoire est en fait allouée à plusieurs morceaux. Ensuite, elle est gérée via une structure zend_mm_huge_list. Une liste chaînée unidirectionnelle est formée entre les grandes mémoires
Le morceau est la granularité minimale pour le. pool de mémoire pour demander et libérer de la mémoire du système. Une liste doublement chaînée est formée entre les morceaux. L'adresse du premier morceau est stockée dans zend_mm_heap->main_chunk, la mémoire de la première page est utilisée pour sauvegarder les membres de la structure. le chunk lui-même, comme les pointeurs des chunks précédents et suivants, l'utilisation de chaque page du chunk actuel, etc.
Les slots de même taille forment une liste chaînée

L'initialisation du chunk Le pool de mémoire est terminé à l'étape php_module_startup. Le processus d'initialisation consiste principalement à allouer la structure du tas. Ce processus est terminé dans le processus start_memory_manager. S'il s'agit d'un environnement multithread, un pool de mémoire sera alloué pour chaque thread. les threads ne s'affecteront pas. Lors de l'initialisation, la variable d'environnement use_zend_alloc_huge_pages sera utilisée pour définir s'il faut activer les pages volumineuses en mémoire. Dans un environnement non thread-safe, le tas alloué sera enregistré dans alloc_globals, qui est la macro AG. Il convient de noter que la structure zend_mm_heap n'est pas allouée séparément et est intégrée dans la structure chunk, car la structure chunk occupe une page, mais en fait elle n'utilise pas beaucoup de mémoire, afin d'utiliser l'espace autant que possible. , il est placé ici

Allocation de mémoire : 1. Une allocation de mémoire énorme dépassant 2 Mo sera alignée sur n morceaux une fois allouée, et une structure zned_mm_huge_list sera également allouée pour gérer toute la mémoire énorme. Le processus d'alignement de la mémoire est ajusté. par le pool de mémoire lui-même après l'application, pas simplement Il est complété par le système d'exploitation. Il s'appliquera une fois en fonction de la taille réelle. Si l'alignement de la mémoire peut simplement être réalisé, aucun ajustement n'est nécessaire et il sera réutilisé directement. S'il ne s'agit pas d'un multiple entier de ZEND_MM_CHUNK_SIZE (2 Mo), zendMM libérera la mémoire et suivra ensuite les instructions Taille de la mémoire réelle + ZEND_MM_CHUNK_SIZE Appliquer à nouveau Le bloc supplémentaire est utilisé pour l'ajustement. 2. Allocation importante : Lorsque la taille de la mémoire appliquée. est compris entre 3072B (3/4page) et 2044k (511 pages), le pool de mémoire sera dans Trouvez le nombre de pages correspondant sur le morceau et renvoyez-le. La granularité de l'application est grande. Il y a deux membres free_map et map sur. le chunk pour enregistrer les informations d'allocation de la page
free_map est de 512 bits, qui est utilisé pour enregistrer l'allocation des pages sur le chunk. Mis à 1 s'il a été utilisé
Map est utilisé pour enregistrer le type d'allocation de. la page et le nombre de pages allouées. Chaque page correspond à un membre du tableau. Les 2 bits les plus élevés enregistrent le type d'allocation de la page 01 est grand, 10 est petit, l'allocation commence à parcourir à partir du premier morceau et vérifie si le morceau a. une page qui répond aux exigences. Si le morceau actuel n'a pas de page appropriée, recherchez le morceau suivant. S'il n'y en a pas jusqu'à la fin, réattribuez un morceau. Lors de la candidature, je ne sais pas. Celui qui trouve un nombre suffisant de pages doit combler autant que possible les espaces vides et les relier autant que possible aux pages allouées pour éviter les espaces vides au milieu (afin de réduire le nombre de recherches lors de l'attribution ultérieure) 1) Du premier Le groupe de morceaux (0 ~ 63) commence à vérifier. Il y a des pages disponibles dans le groupe actuel. Vérifiez d'abord les bits de la page actuelle et trouvez les positions de la première et de la dernière page libre. S'il n'y en a pas assez, marquez ces pages comme. 1 (Alloué), recherchez d'autres groupes, si la page est parfaite, utilisez-la directement et interrompez la récupération. Si la page est plus grande que nécessaire, cela signifie qu'elle est disponible, mais qu'elle n'est pas optimale. pour d'autres morceaux jusqu'à ce qu'un optimal soit finalement trouvé (peut maximiser l'utilisation de la page) 2) Après avoir trouvé la page appropriée, définissez les informations de page correspondantes, c'est-à-dire free_map et les informations de carte, puis renvoyez l'adresse de la page 3. Petit allocation :
Vérifiera d'abord si la mémoire des spécifications correspondantes a été allouée, Si elle n'est pas allouée ou si l'allocation a été épuisée, demandera le nombre de pages correspondant. Le processus d'allocation de pages est le même que celui de. grande allocation. Après avoir postulé pour la page, elle est découpée en emplacements en fonction de la taille fixe. Les emplacements sont connectés à une seule liste chaînée et l'en-tête de la liste chaînée est enregistrée dans AG(mm_heap)->free_slot<.>
La granularité de la libération du pool de mémoire est un bloc, qui est complété via efree 1. La libération de types de mémoire énorme, grande et petite est due au fait que la première page du bloc est occupée, il est donc impossible d'avoir un décalage de 0. par rapport au fragment, il est donc distingué. Lors de la libération du type de fragment et des types grand et petit, le fragment occupé sera libéré et supprimé de la liste chaînée AG en même temps. 2. Libération de grande mémoire : si le décalage calculé. n'est pas 0, cela signifie que l'adresse est grande ou petite mémoire, puis selon Le décalage calcule le numéro de page. Après avoir obtenu la page, vous pouvez obtenir le type d'allocation de la page à partir du chunk->map, et vous pouvez. Libérer la mémoire du type spécifié. Large ne la libérera pas directement, mais définira les informations d'allocation de la page sur Non allouée. S'il s'avère que le morceau n'est pas alloué après la libération, le morceau sera libéré lors de la libération. Il est préférable de déplacer le morceau vers AG. Une fois que le numéro de cache atteint une certaine valeur, le morceau nouvellement ajouté ne sera plus mis en cache et la mémoire sera renvoyée au système, évitez d'occuper trop de mémoire lors de l'allocation de morceaux, si un morceau mis en cache est. trouvé dans chached_chunks, il sera directement extrait et utilisé sans faire d'application au système. 3. Pour une version de type petit, l'emplacement libéré sera directement réinséré dans la liste chaînée disponible de l'emplacement de règle. c'est relativement simple

En C, malloc et free sont utilisés directement pour allouer et libérer de la mémoire. Cependant, l'allocation et la libération fréquentes de mémoire entraîneront une fragmentation de la mémoire et réduiront les performances du système. Les variables PHP seront allouées et libérées très fréquemment. Une allocation de cette manière entraînera de sérieux problèmes de performances. En tant qu'application au niveau du langage, cette perte n'est pas acceptable, c'est pourquoi PHP a implémenté son propre pool de mémoire ZendMM pour remplacer le malloc de la glibc et résoudre gratuitement le problème de l'allocation de mémoire fréquente. 🎜>
Il définit trois opérations de mémoire granulaires de morceau, de page et d'emplacement. La taille de chaque morceau est de 2 Mo et chaque page est de 4 Ko. Un morceau est découpé en 512 pages et chaque page est découpée en plusieurs emplacements. . Lors de la demande de mémoire, différentes stratégies d'allocation sont mises en œuvre en fonction de la taille de l'application
énorme : supérieure à 2 Mo, appelez directement l'allocation système, allouez plusieurs morceaux
grande : demandez une mémoire supérieure à 3092B (3/. 4page) , moins de 2044ko (511page) allouer plusieurs pages
petit : postuler pour une mémoire inférieure à 3092B, le pool mémoire a défini 30 tailles de mémoire différentes à l'avance (8, 16, 32..., 3072), elles sont distribués dans différents Sur la page, lors de la demande de mémoire, recherchez directement l'emplacement correspondant dans la mémoire correspondante. Le pool de mémoire stocke les informations principales du pool de mémoire via la structure zend_mm_heap, telles que la liste chaînée de grande mémoire, la liste chaînée de morceaux, liste chaînée de mémoire de chaque taille d'emplacement, etc.
Grande allocation de mémoire Il s'agit en fait de plusieurs morceaux, qui sont ensuite gérés via une structure zend_mm_huge_list Une liste chaînée unidirectionnelle est formée entre les grandes mémoires
Chunk est la granularité minimale. pour que le pool de mémoire demande et libère de la mémoire du système. Une liste doublement chaînée est formée entre les morceaux. Le premier L'adresse du morceau est stockée dans zend_mm_heap->main_chunk. structurer les membres du chunk lui-même, tels que les pointeurs des chunks précédents et suivants, l'utilisation de chaque page du chunk actuel, etc.
Entre les emplacements de même taille Former une liste à chaînage unique

L'initialisation du pool de mémoire est terminée à l'étape php_module_startup. Le processus d'initialisation consiste principalement à allouer la structure du tas. Ce processus est complété dans le processus start_memory_manager. S'il s'agit d'un environnement multithread, un pool de mémoire sera alloué pour chacun. Les threads ne s'affectent pas les uns les autres. Lors de l'initialisation, la variable d'environnement use_zend_alloc_huge_pages sera utilisée pour définir s'il faut activer les pages volumineuses en mémoire. Dans un environnement non thread-safe, le tas alloué sera enregistré dans alloc_globals, qui est l'AG. macro. Il convient de noter que la structure zend_mm_heap n'est pas allouée séparément, mais est intégrée dans la structure des fragments, car la structure des fragments occupe une page, mais en fait, elle n'utilise pas autant de mémoire pour utiliser l'espace. Dans la mesure du possible, il est placé ici

Allocation de mémoire : 1. Une allocation de mémoire énorme dépassant 2 Mo sera alignée sur n morceaux une fois allouée, et une structure zned_mm_huge_list sera également allouée pour gérer toute la mémoire énorme. L'alignement de la mémoire est le pool de mémoire lui-même après l'application. L'ajustement n'est pas simplement effectué par le système d'exploitation. Il sera appliqué une fois en fonction de la taille réelle. Si l'alignement de la mémoire peut simplement être réalisé, aucun ajustement n'est nécessaire et il sera rétabli. utilisez directement. S'il ne s'agit pas d'un multiple entier de ZEND_MM_CHUNK_SIZE (2 Mo), zendMM le libérera pour ce morceau de mémoire, appliquez-le à nouveau en fonction de la taille réelle de la mémoire + ZEND_MM_CHUNK_SIZE. Le morceau de mémoire supplémentaire demandé est utilisé pour l'ajustement. 2. Allocation importante : la taille de la mémoire appliquée est comprise entre 3 072 B (3/4 page) et 2 044 Ko (511 pages), le pool de mémoire recherchera le nombre de pages correspondant sur le bloc et le renverra. La granularité de l'application est grande. page. Il y a deux membres free_map et map sur le chunk pour enregistrer les informations d'allocation de la page
free_map est de 512 bits, qui est utilisé pour enregistrer l'état d'allocation de la page sur le chunk. il est défini sur 1
La carte est utilisée pour enregistrer le type d'allocation de la page et le nombre de pages allouées. Chaque page correspond à un membre du tableau. Les 2 bits les plus élevés enregistrent le type d'allocation 01 est Large. et 10 sont petits. Lors de l'allocation, commencez à parcourir à partir du premier morceau et vérifiez si le morceau a une page qui répond aux exigences. Si le morceau actuel n'a pas de page appropriée, recherchez le morceau suivant. jusqu'à la fin, réaffectez-le. Lors de la demande d'un morceau, je ne sais pas qui a trouvé suffisamment de pages. Au lieu de cela, j'essaie de combler autant que possible les lacunes du morceau et de les relier autant que possible aux pages allouées. pour éviter les espaces entre les pages au milieu (pour réduire le temps d'allocation ultérieure). Le nombre de recherches) 1) Commencez la vérification à partir du premier groupe de blocs (0 ~ 63). Si le groupe actuel a des pages disponibles, détectez d'abord les bits de. la page actuelle et recherchez les positions des première et dernière pages libres. S'il n'y en a pas assez, alors ces pages sont marquées comme 1 (attribuées), et d'autres groupes sont recherchés. Si la page est parfaite, elle est utilisée directement et. la récupération est interrompue. Si la page est plus grande que nécessaire, cela signifie qu'elle est disponible, mais qu'elle n'est pas optimale, et d'autres morceaux seront recherchés jusqu'à la fin. Comparez celui qui est optimal (celui qui peut maximiser l'utilisation de la page). ) 2) Après avoir trouvé la page appropriée, définissez les informations de page correspondantes, c'est-à-dire free_map et les informations de carte, puis renvoyez l'adresse de la page 3. Petite allocation :
vérifiera d'abord la page correspondante si la mémoire spécifiée a été allouée ? S'il n'a pas été alloué ou si l'allocation a été épuisée, demandez des pages avec le nombre de pages correspondant. Le processus d'attribution de pages est cohérent avec une allocation importante. Après avoir demandé la page, elle est découpée en emplacements selon le nombre fixe. taille et des emplacements uniques sont utilisés entre les emplacements de connexion de liste chaînée, la tête de la liste chaînée est enregistrée dans AG(mm_heap)->free_slot


La granularité de la libération du pool de mémoire est un bloc, qui est complété via efree 1. La libération des types de mémoire énormes, grands et petits est due au fait que la première page du bloc est occupée, il est donc impossible d'avoir un décalage relatif de 0. au chunk, afin qu'il puisse être distingué. Lors de la libération du type de chunk et des types grand et petit, le chunk occupé sera libéré et supprimé de la liste chaînée AG en même temps 2. Libération de grande mémoire : Si le décalage calculé. n'est pas 0, cela signifie que l'adresse est grande ou petite mémoire, puis selon Le décalage calcule le numéro de page. Après avoir obtenu la page, vous pouvez obtenir le type d'allocation de la page à partir du chunk->map, et vous pouvez. Libérer la mémoire du type spécifié. Large ne la libérera pas directement, mais définira les informations d'allocation de la page sur Non allouée. S'il s'avère que le morceau n'est pas alloué après la libération, le morceau sera libéré lors de la libération. Il est préférable de déplacer le morceau vers AG. Une fois que le numéro de cache atteint une certaine valeur, le morceau nouvellement ajouté ne sera plus mis en cache et la mémoire sera renvoyée au système, évitez d'occuper trop de mémoire lors de l'allocation de morceaux, si un morceau mis en cache est. trouvé dans chached_chunks, il sera directement extrait et utilisé sans faire d'application au système. 3. Pour une version de type petit, l'emplacement libéré sera directement réinséré dans la liste chaînée disponible de l'emplacement de règle. Juste la tête, relativement. simple.

Recommandations associées :

Explication des exemples de gestion de la mémoire JS

Introduction détaillée à la gestion de la mémoire sous Linux

Notes d'étude sur les variables PHP et la gestion de la mémoire

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!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
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
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal
À propos de nous Clause de non-responsabilité Sitemap
Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!