Maison > Article > développement back-end > Une brève discussion du code source PHP 31 : bases de la couche de tas dans le pool de mémoire PHP
Cet article présente principalement le code source PHP 31 : la base de la couche de tas dans le pool de mémoire PHP, qui a une certaine valeur de référence. Maintenant, je le partage avec vous. Les amis dans le besoin peuvent s'y référer
<.>
Le gestionnaire de mémoire de PHP est hiérarchique . Ce gestionnaire comporte trois couches : la couche de stockage, la couche tas et la couche emalloc/efree. La couche de stockage est introduite dans les notes de lecture du code source PHP 30 : Couche de stockage dans le pool de mémoire PHP La couche de stockage applique en fait de la mémoire au système via des fonctions telles que malloc() et mmap(), et libère la mémoire demandée via la mémoire libre. () fonction Mémoire. La couche de stockage s'applique généralement aux blocs de mémoire plus grands. La grande mémoire appliquée ici ne signifie pas la mémoire requise par la structure de la couche de stockage. C'est simplement que lorsque la couche de tas appelle la méthode d'allocation de la couche de stockage, la mémoire qu'elle demande est utilisée. le format du segment est relativement grand, le rôle de la couche de stockage est de rendre la méthode d'allocation de mémoire transparente pour la couche de tas.
Au-dessus de la couche de stockage se trouve la couche de tas que nous voulons en savoir plus aujourd'hui. La couche de tas est une couche de planification qui interagit avec la couche emalloc/efree ci-dessus pour diviser les gros blocs de mémoire demandés via la couche de stockage et les fournir à la demande. Il existe un ensemble de stratégies de planification de la mémoire dans la couche de tas, qui constitue la zone centrale de toute la gestion de l'allocation de mémoire PHP.
Regardez d'abord les structures impliquées dans la couche de tas :
[Structure]
/* mm block type */typedef struct _zend_mm_block_info { size_t _size;/* block的大小*/ size_t _prev;/* 计算前一个块有用到*/} zend_mm_block_info; typedef struct _zend_mm_block { zend_mm_block_info info;} zend_mm_block; typedef struct _zend_mm_small_free_block {/* 双向链表 */ zend_mm_block_info info; struct _zend_mm_free_block *prev_free_block;/* 前一个块 */ struct _zend_mm_free_block *next_free_block;/* 后一个块 */} zend_mm_small_free_block;/* 小的空闲块*/ typedef struct _zend_mm_free_block {/* 双向链表 + 树结构 */ zend_mm_block_info info; struct _zend_mm_free_block *prev_free_block;/* 前一个块 */ struct _zend_mm_free_block *next_free_block;/* 后一个块 */ struct _zend_mm_free_block **parent;/* 父结点 */ struct _zend_mm_free_block *child[2];/* 两个子结点*/} zend_mm_free_block; struct _zend_mm_heap { int use_zend_alloc;/* 是否使用zend内存管理器 */ void *(*_malloc)(size_t);/* 内存分配函数*/ void (*_free)(void*);/* 内存释放函数*/ void *(*_realloc)(void*, size_t); size_t free_bitmap;/* 小块空闲内存标识 */ size_t large_free_bitmap; /* 大块空闲内存标识*/ size_t block_size;/* 一次内存分配的段大小,即ZEND_MM_SEG_SIZE指定的大小,默认为ZEND_MM_SEG_SIZE (256 * 1024)*/ size_t compact_size;/* 压缩操作边界值,为ZEND_MM_COMPACT指定大小,默认为 2 * 1024 * 1024*/ zend_mm_segment *segments_list;/* 段指针列表 */ zend_mm_storage *storage;/* 所调用的存储层 */ size_t real_size;/* 堆的真实大小 */ size_t real_peak;/* 堆真实大小的峰值 */ size_t limit;/* 堆的内存边界 */ size_t size;/* 堆大小 */ size_t peak;/* 堆大小的峰值*/ size_t reserve_size;/* 备用堆大小*/ void *reserve;/* 备用堆 */ int overflow;/* 内存溢出数*/ int internal;#if ZEND_MM_CACHE unsigned int cached;/* 已缓存大小 */ zend_mm_free_block *cache[ZEND_MM_NUM_BUCKETS];/* 缓存数组/ #endif zend_mm_free_block *free_buckets[ZEND_MM_NUM_BUCKETS*2];/* 小块空闲内存数组 */ zend_mm_free_block *large_free_buckets[ZEND_MM_NUM_BUCKETS];/* 大块空闲内存数组*/ zend_mm_free_block *rest_buckets[2];/* 剩余内存数组 */ };Pour la fonction d'opération de mémoire dans la structure de tas, si use_zend_alloc est non, l'allocation de mémoire de type malloc est used , à l'heure actuelle, toutes les opérations ne passent pas par la gestion de la mémoire dans la couche tas, mais utilisent directement des fonctions telles que malloc. La taille de compact_size est par défaut de 2 * 1024 * 1024 (2M). Si la variable ZEND_MM_COMPACT est définie, spécifiez la taille pour cela. Si le pic de mémoire dépasse cette valeur, la fonction compacte de stockage sera appelée. , juste cette fonction L'implémentation actuelle est vide et peut être ajoutée dans les versions ultérieures. reserve_size est la taille du tas de réserve, par défaut c'est ZEND_MM_RESERVE_SIZE, sa taille est (8*1024)
*reserve est le tas de réserve, sa taille est reserve_size, il est utilisé pour signaler les erreurs quand la mémoire déborde.
La variable d'environnement USE_ZEND_ALLOC peut être utilisée pour permettre la sélection de l'allocation de mémoire malloc ou emalloc au moment de l'exécution. L'utilisation de l'allocation de mémoire de type malloc permettra aux débogueurs externes d'observer l'utilisation de la mémoire, tandis que l'allocation emalloc utilisera l'abstraction du gestionnaire de mémoire Zend, nécessitant un débogage interne.
[zend_startup() -> start_memory_manager() -> alloc_globals_ctor()]
static void alloc_globals_ctor(zend_alloc_globals *alloc_globals TSRMLS_DC){ char *tmp; alloc_globals->mm_heap = zend_mm_startup(); tmp = getenv("USE_ZEND_ALLOC"); if (tmp) { alloc_globals->mm_heap->use_zend_alloc = zend_atoi(tmp, 0); if (!alloc_globals->mm_heap->use_zend_alloc) {/* 如果不使用zend的内存管理器,同直接使用malloc函数*/ alloc_globals->mm_heap->_malloc = malloc; alloc_globals->mm_heap->_free = free; alloc_globals->mm_heap->_realloc = realloc; } }}[Initialisation][zend_mm_startup()]
Initialiser la couche de stockage Plan d'allocation, initialisez la taille du segment, la valeur limite de compression et appelez zend_mm_startup_ex() pour initialiser la couche de tas.
[Alignement de la mémoire]
L'alignement de la mémoire est utilisé dans le calcul de l'alignement de la mémoire PHP a évidemment deux objectifs : l'un est de réduire le nombre. des accès mémoire par le CPU ; la seconde est de maintenir l'efficacité de l'espace de stockage suffisamment élevée.
# define ZEND_MM_ALIGNMENT 8 #define ZEND_MM_ALIGNMENT_MASK ~(ZEND_MM_ALIGNMENT-1) #define ZEND_MM_ALIGNED_SIZE(size)(((size) + ZEND_MM_ALIGNMENT - 1) & ZEND_MM_ALIGNMENT_MASK) #define ZEND_MM_ALIGNED_HEADER_SIZEZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_block)) #define ZEND_MM_ALIGNED_FREE_HEADER_SIZEZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_small_free_block))PHP utilise l'alignement de la mémoire pour allouer la mémoire du bloc. Si les trois chiffres inférieurs de la taille de mémoire requise ne sont pas 0 (non divisibles par 8), ajoutez les trois chiffres inférieurs 7 et effectuez un ET. l'opération avec ~7, c'est-à-dire que la taille de la mémoire qui n'est pas un multiple entier de 8 est terminée jusqu'à ce qu'elle puisse être divisée de manière égale par 8.
Sur les machines win32, les tailles numériques correspondant à certaines macros sont :
ZEND_MM_MIN_SIZE=8
ZEND_MM_MAX_SMALL_SIZE=272
ZEND_MM_ALIGNED_HEADER_SIZE=8
ZEND_MM_ALIGNED_FREE_HEADER_SIZE=16
ZEND_MM_MIN _ALLOC_BLOCK_SIZE=8
ZEND_MM_ALIGNED_MIN_HEADER_SIZE =16
ZEND_MM_ALIGNED_SEGMENT_SIZE=8
Les deux chiffres de droite de la mémoire allouée sont utilisés pour marquer le type de mémoire.
La définition de sa taille est #define ZEND_MM_TYPE_MASK ZEND_MM_LONG_CONST(0×3)
#define ZEND_MM_NEXT_BLOCK(b)ZEND_MM_BLOCK_AT(b, ZEND_MM_BLOCK_SIZE(b)) #define ZEND_MM_PREV_BLOCK(b)ZEND_MM_BLOCK_AT(b, -(int)((b)->info._prev & ~ZEND_MM_TYPE_MASK)) #define ZEND_MM_BLOCK_AT(blk, offset)((zend_mm_block *) (((char *) (blk))+(offset))) #define ZEND_MM_BLOCK_SIZE(b)((b)->info._size & ~ZEND_MM_TYPE_MASK)#define ZEND_MM_TYPE_MASKZEND_MM_LONG_CONST(0x3)L'élément suivant du bloc actuel est la position actuelle de la tête du bloc plus la longueur du bloc entier (moins la longueur du type).
L'élément précédent du bloc actuel est la position de la tête du bloc actuel moins la longueur du bloc précédent (en supprimant la longueur du type).
Concernant la longueur du bloc précédent, elle est définie sur le résultat de l'opération OU de la taille actuelle du bloc et du type de bloc lors de l'initialisation du bloc.
Une brève discussion du code source PHP 30 : La couche de stockage dans le pool de mémoire PHP
Une brève discussion du code source PHP vingt-neuf : à propos de l'héritage des interfaces
Une brève discussion du code source PHP vingt-huit : à propos de la structure et de l'héritage des classes
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!