詳解PHP記憶體池中的儲存層

2021-06-14 01:16:36 字數 3953 閱讀 6673

php的記憶體管理器是分層(hierarchical)的。這個管理器共有三層:儲存層(storage)、堆(heap)層和 emalloc/efree 層。儲存層通過 malloc()、mmap() 等函式向系統真正的申請記憶體,並通過free()函式釋放所申請的記憶體。

儲存層通常申請的記憶體塊都比較大,這裡申請的記憶體大並不是指storage層結構所需要的記憶體大,只是堆層通過呼叫儲存層的分配方法時,其以段的格式申請的記憶體比較大,儲存層的作用是將記憶體分配的方式對堆層透明化。

首先看storage層的結構:

/* heaps with user defined storage */  

typedef struct _zend_mm_storage zend_mm_storage;  

typedef struct _zend_mm_segment  zend_mm_segment;  

typedef struct _zend_mm_mem_handlers  zend_mm_mem_handlers;  

struct _zend_mm_storage ;  

記憶體的分配方式,呼叫的函式是_zend_mm_storage結構中的處理函式集,而記憶體是以段的形式表現的。

4種記憶體方案

php在儲存層共有4種記憶體分配方案: malloc,win32,mmap_anon,mmap_zero。預設使用malloc分配記憶體,如果設定了zend_win32巨集,則為windows版本,呼叫heapalloc分配記憶體,剩下兩種記憶體方案為匿名記憶體對映,並且php的記憶體方案可以通過設定變數來修改。

官方說明如下:

the zend mm can be tweaked using zend_mm_mem_type and zend_mm_seg_size environment variables. default values are 「malloc」 and 「256k」.dependent on target system you can also use 「mmap_anon」, 「mmap_zero」 and 「win32″ storage managers.

在**中,對於這4種記憶體分配方案,分別對應實現了zend_mm_mem_handlers中的各個處理函式。配合**的簡單說明如下:

/* 使用mmap記憶體對映函式分配記憶體 寫入時拷貝的私有對映,並且匿名對映,對映區不與任何檔案關聯。*/  

# define zend_mm_mem_mmap_anon_dsc   

/* 使用mmap記憶體對映函式分配記憶體 寫入時拷貝的私有對映,並且對映到/dev/zero。*/  

# define zend_mm_mem_mmap_zero_dsc   

/* 使用heapalloc分配記憶體 windows版本 關於這點,注釋中寫的是virtualalloc() to allocate memory,實際在程式中使用的是heapalloc*/  

# define zend_mm_mem_win32_dsc   

/* 使用malloc分配記憶體 預設為此種分配 如果有加zend_win32巨集,則使用win32的分配方案*/  

# define zend_mm_mem_malloc_dsc   

static const zend_mm_mem_handlers mem_handlers =   

};關於匿名記憶體對映的優點

mmem_zero方案:

1. 可以將偽裝置 「/dev/zero」 作為引數傳遞給mmap而建立乙個對映區。/dev/zero的特殊在於,對於該裝置檔案所有的讀操作都返回值為0的指定長度的位元組流 ,任何寫入的內容都被丟棄。我們的興趣在於用它來建立對映區,用/dev/zero建立的對映區,其內容被初始為0。

2. 使用/dev/zero的優點在於,mmap建立對映區時,不需要乙個時間存在的檔案,偽檔案 /dev/zero 就足夠了。缺點是只能用在相關程序間。相對於相關程序間的通訊,使用執行緒間通訊效率要更高一些。不管使用那種技術,對共享資料的訪問都需要進行同步。

mmem_anon方案:

1. 匿名記憶體對映與使用/dev/zero型別,都不需要真實的檔案。要使用匿名對映之需要向mmap傳入map_anon標誌,並且fd引數置為-1。

2. 所謂匿名,指的是對映區並沒有通過fd與檔案路徑名相關聯。匿名記憶體對映用在有血緣關係的程序間。

win32方案中堆記憶體分配的宣告

函式heapalloc宣告如下:

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,  

__in dword dwflags,  

__deref lpvoid lpmem  

);  

winbaseapi  

size_t  

winapi  

heapsize(  

__in handle hheap,  

__in dword dwflags,  

__in lpcvoid lpmem  

);

◆hheap是程序堆記憶體開始位置。

◆dwflags是分配堆記憶體的標誌。

◆dwbytes是分配堆記憶體的大小。

初始化

在zend_mm_startup啟動時,程式會根據配置設定記憶體分配方案和段分配大小,如下所示**:

zend_api zend_mm_heap *zend_mm_startup(void)  

else   

}  if (!mem_handlers[i].name)   

exit(255);  

}  }  

handlers = &mem_handlers[i];  

tmp = getenv("zend_mm_seg_size");  

if (tmp)  else if (seg_size <

zend_mm_aligned_segment_size + zend_mm_aligned_header_size)   

} else   

//....**省略  

}

第1121~1138行遍歷整個mem_handlers陣列,確認記憶體分配方案,如果沒有設定zend_mm_mem_type變數,預設使用malloc方案,如果是windows(即zend_win32),則預設使用win32方案,如果設定了zend_mm_mem_type變數,則採用設定的方案。

第1140~1152行確認段分配大小,如果設定了zend_mm_seg_size變數,則使用設定的大小,此處會判斷所設定的大小是否滿足2的倍數,並且大於或等於zend_mm_aligned_segment_size + zend_mm_aligned_header_size;如果沒有設定沒使用預設的zend_mm_seg_size。

詳解PHP記憶體池中的儲存層

php的記憶體管理器是分層 hierarchical 的。這個管理器共有三層 儲存層 storage 堆 heap 層和 emalloc efree 層。儲存層通過 malloc mmap 等函式向系統真正的申請記憶體,並通過free 函式釋放所申請的記憶體。儲存層通常申請的記憶體塊都比較大,這裡申...

PHP變數在記憶體中的儲存方式

每門計算機語言都需要一些容器來儲存變數資料。在一些語言當中,變數都有特定的型別,如字串,陣列,物件等等。比如c和pascal就屬於這種。而php則沒有這樣的型別。在php中,乙個變數在某一行是字串,可能到下一行就變成了數字。變數可以經常在不同的型別間輕易的轉化,甚至是自動的轉 換。php之所以成為乙...

記憶體儲存 第4p,記憶體 硬碟,計算機的儲存器詳解

對於儲存器,每個人都希望它儲存速度超級快 儲存容量超級大 造價便宜 速度快 容量大 造價低 但同時兼得這三者是不可能的,所以根據不同的需求產生了不同的儲存器 1 暫存器 暫存器用與cpu相同材質製造,與cpu一樣快,因而cpu訪問它無時延,典型容量是 在32位cpu中為32 32,在64位cpu中為...