Maison  >  Article  >  développement back-end  >  Une brève discussion du code source PHP 30 : couche de stockage dans le pool de mémoire PHP

Une brève discussion du code source PHP 30 : couche de stockage dans le pool de mémoire PHP

不言
不言original
2018-06-29 09:41:411460parcourir

Cet article présente principalement le code source PHP 30 : La couche de stockage dans le pool de mémoire PHP a une certaine valeur de référence. Maintenant, je la partage avec vous. Les amis dans le besoin peuvent s'y référer

En parlant de PHP. code source 30 : La couche de stockage 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 demande 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 fonction free(). 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.

Regardez d'abord la structure de la couche de stockage :
[Structure]

  /* Heaps with user defined storage */
  typedef struct _zend_mm_storage zend_mm_storage; typedef struct _zend_mm_segment {
    size_t    size;
    struct _zend_mm_segment *next_segment;
    } 
    zend_mm_segment; 
    typedef struct _zend_mm_mem_handlers {
    const char *name;
    zend_mm_storage* (*init)(void *params);    //    初始化函数
    void (*dtor)(zend_mm_storage *storage);    //    析构函数
    void (*compact)(zend_mm_storage *storage);
    zend_mm_segment* (*_alloc)(zend_mm_storage *storage, size_t size);    //    内存分配函数
    zend_mm_segment* (*_realloc)(zend_mm_storage *storage, zend_mm_segment *ptr, size_t size);    //    重新分配内存函数
    void (*_free)(zend_mm_storage *storage, zend_mm_segment *ptr);    //    释放内存函数
    } 
    zend_mm_mem_handlers; struct _zend_mm_storage {
    const zend_mm_mem_handlers *handlers;    //    处理函数集
    void *data;};

La méthode d'allocation de mémoire, la fonction appelée est la fonction de traitement définie dans la structure _zend_mm_storage, et la mémoire est basée sur Exprimé sous forme de segments.
[4 schémas de mémoire]
PHP a 4 schémas d'allocation de mémoire dans la couche de stockage : malloc, win32, mmap_anon, mmap_zero Par défaut, malloc est utilisé pour allouer de la mémoire. Si la macro ZEND_WIN32 est définie, c'est la. version Windows et appelle HeapAlloc pour allouer de la mémoire, les deux schémas de mémoire restants sont un mappage de mémoire anonyme et le schéma de mémoire de PHP peut être modifié en définissant des variables.
La description officielle est la suivante :
Le Zend MM peut être modifié en utilisant les environnements ZEND_MM_MEM_TYPE et ZEND_MM_SEG_SIZE
Les valeurs par défaut sont "malloc" et "256K". peut également utiliser les gestionnaires de stockage « mmap_anon », « mmap_zero » et « win32″.

Dans le code, pour ces quatre schémas d'allocation de mémoire, chaque fonction de traitement dans zend_mm_mem_handlers est implémentée respectivement. Une description simple du code est la suivante :

/* 使用mmap内存映射函数分配内存 写入时拷贝的私有映射,并且匿名映射,映射区不与任何文件关联。*/
# define ZEND_MM_MEM_MMAP_ANON_DSC {"mmap_anon", zend_mm_mem_dummy_init, zend_mm_mem_dummy_dtor, zend_mm_mem_dummy_compact, zend_mm_mem_mmap_anon_alloc, zend_mm_mem_mmap_realloc, zend_mm_mem_mmap_free}
/* 使用mmap内存映射函数分配内存 写入时拷贝的私有映射,并且映射到/dev/zero。*/
# define ZEND_MM_MEM_MMAP_ZERO_DSC {"mmap_zero", zend_mm_mem_mmap_zero_init, zend_mm_mem_mmap_zero_dtor, zend_mm_mem_dummy_compact, zend_mm_mem_mmap_zero_alloc, zend_mm_mem_mmap_realloc, zend_mm_mem_mmap_free}
/* 使用HeapAlloc分配内存 windows版本 关于这点,注释中写的是VirtualAlloc() to allocate memory,实际在程序中使用的是HeapAlloc*/
# define ZEND_MM_MEM_WIN32_DSC {"win32", zend_mm_mem_win32_init, zend_mm_mem_win32_dtor, zend_mm_mem_win32_compact, zend_mm_mem_win32_alloc, zend_mm_mem_win32_realloc, zend_mm_mem_win32_free}
/* 使用malloc分配内存 默认为此种分配 如果有加ZEND_WIN32宏,则使用win32的分配方案*/
# define ZEND_MM_MEM_MALLOC_DSC {"malloc", zend_mm_mem_dummy_init, zend_mm_mem_dummy_dtor, zend_mm_mem_dummy_compact, zend_mm_mem_malloc_alloc, zend_mm_mem_malloc_realloc, zend_mm_mem_malloc_free}static const zend_mm_mem_handlers mem_handlers[] = {#ifdef HAVE_MEM_WIN32    
ZEND_MM_MEM_WIN32_DSC,#endif#ifdef HAVE_MEM_MALLOC    ZEND_MM_MEM_MALLOC_DSC,#endif#ifdef HAVE_MEM_MMAP_ANON    
ZEND_MM_MEM_MMAP_ANON_DSC,#endif#ifdef HAVE_MEM_MMAP_ZERO    
ZEND_MM_MEM_MMAP_ZERO_DSC,#endif    
{NULL, NULL, NULL, NULL, NULL, NULL}};
[À propos des avantages du mappage de mémoire anonyme]

Solution mmem_zero :
(SVR 4) /dev/zero Memory Mapping
1. Vous pouvez Le pseudo-périphérique "/dev/zero" est passé en paramètre à mmap pour créer une zone de mappage. La particularité de /dev/zero est que toutes les opérations de lecture sur ce fichier de périphérique renvoient un flux d'octets de la longueur spécifiée avec une valeur de 0, et tout contenu écrit est ignoré. Notre intérêt réside dans son utilisation pour créer une zone de mappage. Le contenu de la zone de mappage créée avec /dev/zero est initialisé à 0.
2. L'avantage d'utiliser /dev/zero est que lorsque mmap crée la zone de mappage, il n'a pas besoin d'un fichier qui existe à tout moment. Le pseudo fichier /dev/zero suffit. L’inconvénient est qu’il ne peut être utilisé qu’entre des processus liés. Par rapport à la communication entre processus associés, il est plus efficace d’utiliser la communication inter-thread. Quelle que soit la technologie utilisée, l’accès aux données partagées doit être synchronisé.

Solution mmem_anon :

(4.4 BSD) Mappage de mémoire anonyme
1. Le mappage de mémoire anonyme et l'utilisation du type /dev/zero ne nécessitent pas de vrais fichiers. Pour utiliser le mappage anonyme, vous devez transmettre l'indicateur MAP_ANON à mmap et définir le paramètre fd sur -1.
2. Ce qu'on appelle anonyme signifie que la zone de mappage n'est pas associée au nom du chemin du fichier via fd. La cartographie mémoire anonyme est utilisée entre les processus liés par le sang.

[Déclaration de l'allocation de mémoire du tas dans le schéma win32]

API Windows
La fonction HeapAlloc est déclarée comme suit :

WINBASEAPI
__out_opt
HANDLE
WINAPI
HeapCreate(
__in DWORD flOptions,
__in SIZE_T dwInitialSize,
__in SIZE_T dwMaximumSize); 
WINBASEAPI
BOOL
WINAPI
HeapDestroy(
__in HANDLE hHeap); 
WINBASEAPI
__bcount(dwBytes)LPVOID
WINAPI
HeapAlloc(
__in HANDLE hHeap,
__in DWORD dwFlags,
__in SIZE_T dwBytes); 
 
WINBASEAPI
BOOL
WINAPI
HeapFree(
__inout HANDLE hHeap,
__inDWORD dwFlags,
__deref LPVOID lpMem); 
WINBASEAPI
SIZE_T
WINAPI
HeapSize(
__in HANDLE hHeap,
__in DWORD dwFlags,
__in LPCVOID lpMem);
hHeap est l'emplacement de départ du tas de processus mémoire.

dwFlags est l'indicateur pour allouer de la mémoire tas.
dwBytes est la taille de la mémoire tas allouée.

[Initialisation]

Lorsque zend_mm_startup est démarré, le programme définira le plan d'allocation de mémoire et la taille d'allocation de segment en fonction de la configuration, comme indiqué dans le code suivant :

ZEND_API zend_mm_heap *zend_mm_startup(void){
    int i;
    size_t seg_size;
    char *mem_type = getenv("ZEND_MM_MEM_TYPE");
    char *tmp;
    const zend_mm_mem_handlers *handlers;
    zend_mm_heap *heap;     if (mem_type == NULL) {
    i = 0;
    } else {
    for (i = 0; mem_handlers[i].name; i++) {
    if (strcmp(mem_handlers[i].name, mem_type) == 0) {
    break;
    }
    }
    if (!mem_handlers[i].name) {
    fprintf(stderr, "Wrong or unsupported zend_mm storage type '%s'\n", mem_type);
    fprintf(stderr, "  supported types:\n");
    for (i = 0; mem_handlers[i].name; i++) {
    fprintf(stderr, "'%s'\n", mem_handlers[i].name);
    }
    exit(255);
    }
    }
    handlers = &mem_handlers[i]; 
    tmp = getenv("ZEND_MM_SEG_SIZE");
    if (tmp) {
    seg_size = zend_atoi(tmp, 0);
    if (zend_mm_low_bit(seg_size) != zend_mm_high_bit(seg_size)) {
    fprintf(stderr, "ZEND_MM_SEG_SIZE must be a power of two\n");
    exit(255);
    } else if (seg_size < ZEND_MM_ALIGNED_SEGMENT_SIZE + ZEND_MM_ALIGNED_HEADER_SIZE) {
    fprintf(stderr, "ZEND_MM_SEG_SIZE is too small\n");
    exit(255);
    }
    } else {
    seg_size = ZEND_MM_SEG_SIZE;
    }     //....代码省略}
Traversez les lignes 1121~1138 Pour l'ensemble du tableau mem_handlers, confirmez le schéma d'allocation de mémoire Si la variable ZEND_MM_MEM_TYPE n'est pas définie, le schéma malloc est utilisé par défaut. S'il s'agit de Windows (c'est-à-dire ZEND_WIN32), le schéma win32 est utilisé par défaut. Si la variable ZEND_MM_MEM_TYPE est définie, le schéma défini est utilisé.

Les lignes 1140~1152 confirment la taille d'allocation du segment. Si la variable ZEND_MM_SEG_SIZE est définie, la taille définie sera utilisée Ici, il sera jugé si la taille définie satisfait un multiple de 2 et est supérieure ou supérieure. égal à ZEND_MM_ALIGNED_SEGMENT_SIZE + ZEND_MM_ALIGNED_HEADER_SIZE ; S'il n'y a pas de paramètre, le ZEND_MM_SEG_SIZE par défaut n'est pas utilisé

[Annexe]

Description de la fonction :
mmap mappe un fichier ou un autre objet en mémoire. Le fichier est mappé sur plusieurs pages. Si la taille du fichier n'est pas la somme des tailles de toutes les pages, l'espace inutilisé de la dernière page sera effacé. munmap effectue l'opération inverse, supprimant le mappage d'objets pour une plage d'adresses spécifique.
Mappage basé sur un fichier, à tout moment pendant l'exécution de mmap et munmap, le st_atime du fichier mappé peut être mis à jour. Si le champ st_atime n'est pas mis à jour dans la situation ci-dessus, la valeur de ce champ sera mise à jour lorsque la première page de la zone cartographiée sera indexée pour la première fois. Pour un mappage de fichier établi avec les indicateurs PROT_WRITE et MAP_SHARED, ses st_ctime et st_mtime
seront mis à jour après l'écriture dans la zone de mappage, mais avant que msync() ne soit appelé avec les indicateurs MS_SYNC et MS_ASYNC.

Utilisation :


#include 
void *mmap(void *start, size_t length, int prot, int flags,
int fd, off_t offset);
int munmap(void *start, size_t length);

参数:
start:映射区的开始地址。
length:映射区的长度。
prot:期望的内存保护标志,不能与文件的打开模式冲突。是以下的某个值,可以通过or运算合理地组合在一起
PROT_EXEC //页内容可以被执行
PROT_READ //页内容可以被读取
PROT_WRITE //页可以被写入
PROT_NONE //页不可访问
flags:指定映射对象的类型,映射选项和映射页是否可以共享。它的值可以是一个或者多个以下位的组合体
MAP_FIXED //使用指定的映射起始地址,如果由start和len参数指定的内存区重叠于现存的映射空间,重叠部分将会被丢弃。如果指定的起始地址不可用,操作将会失败。并且起始地址必须落在页的边界上。
MAP_SHARED //与其它所有映射这个对象的进程共享映射空间。对共享区的写入,相当于输出到文件。直到msync()或者munmap()被调用,文件实际上不会被更新。
MAP_PRIVATE //建立一个写入时拷贝的私有映射。内存区域的写入不会影响到原文件。这个标志和以上标志是互斥的,只能使用其中一个。
MAP_DENYWRITE //这个标志被忽略。
MAP_EXECUTABLE //同上
MAP_NORESERVE //不要为这个映射保留交换空间。当交换空间被保留,对映射区修改的可能会得到保证。当交换空间不被保留,同时内存不足,对映射区的修改会引起段违例信号。
MAP_LOCKED //锁定映射区的页面,从而防止页面被交换出内存。
MAP_GROWSDOWN //用于堆栈,告诉内核VM系统,映射区可以向下扩展。
MAP_ANONYMOUS //匿名映射,映射区不与任何文件关联。
MAP_ANON //MAP_ANONYMOUS的别称,不再被使用。
MAP_FILE //兼容标志,被忽略。
MAP_32BIT //将映射区放在进程地址空间的低2GB,MAP_FIXED指定时会被忽略。当前这个标志只在x86-64平台上得到支持。
MAP_POPULATE //为文件映射通过预读的方式准备好页表。随后对映射区的访问不会被页违例阻塞。
MAP_NONBLOCK //仅和MAP_POPULATE一起使用时才有意义。不执行预读,只为已存在于内存中的页面建立页表入口。
fd:有效的文件描述词。如果MAP_ANONYMOUS被设定,为了兼容问题,其值应为-1。
offset:被映射对象内容的起点。

返回说明:
成功执行时,mmap()返回被映射区的指针,munmap()返回0。失败时,mmap()返回MAP_FAILED[其值为(void *)-1],munmap返回-1。errno被设为以下的某个值
EACCES:访问出错
EAGAIN:文件已被锁定,或者太多的内存已被锁定
EBADF:fd不是有效的文件描述词
EINVAL:一个或者多个参数无效
ENFILE:已达到系统对打开文件的限制
ENODEV:指定文件所在的文件系统不支持内存映射
ENOMEM:内存不足,或者进程已超出最大内存映射数量
EPERM:权能不足,操作不允许
ETXTBSY:已写的方式打开文件,同时指定MAP_DENYWRITE标志
SIGSEGV:试着向只读区写入
SIGBUS:试着访问不属于进程的内存区

以上就是本文的全部内容,希望对大家的学习有所帮助,更多相关内容请关注PHP中文网!

相关推荐:

浅谈PHP源码二十九:关于接口的继承

浅谈PHP源码二十八:关于类结构和继承

浅谈PHP源码二十七:PHP对构造方法的识别

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