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

Une brève discussion du code source PHP 31 : bases de la couche de tas dans le pool de mémoire PHP

不言
不言original
2018-06-29 09:50:102178parcourir

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
<.>

Une brève discussion du code source PHP 31 : Les bases de la couche de tas dans le pool de mémoire PHP

[Présentation]

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.

Tous les partages ci-dessous sont basés sur le fait que ZEND_DEBUG n'est pas ouvert.

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.

【À propos de USE_ZEND_ALLOC】

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.

[zend_mm_startup() -> zend_mm_startup_ex()]

[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

Si vous souhaitez allouer un bloc d'une taille de 9 octets, sa taille réellement allouée est ZEND_MM_ALIGNED_SIZE(9 + 8)=24

[Positionnement du bloc 】

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)

Le code ci-dessous est le positionnement du bloc

 #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.

Ce qui précède représente l'intégralité du contenu de cet article. J'espère qu'il sera utile à l'étude de chacun. Pour plus de contenu connexe, veuillez faire attention au site Web PHP chinois !

Recommandations associées :

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!

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