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

2021-08-27 12:01:03 字數 3786 閱讀 2694

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

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

首先看storage層的結構:

/*heapswithuserdefinedstorage*/ 

typedefstruct_zend_mm_storagezend_mm_storage;

typedefstruct_zend_mm_segmentzend_mm_segment;

typedefstruct_zend_mm_mem_handlerszend_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記憶體對映函式分配記憶體寫入時拷貝的私有對映,並且匿名對映,對映區不與任何檔案關聯。*/ 

#definezend_mm_mem_mmap_anon_dsc

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

#definezend_mm_mem_mmap_zero_dsc

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

#definezend_mm_mem_win32_dsc

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

#definezend_mm_mem_malloc_dsc

staticconstzend_mm_mem_handlersmem_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(

__indwordfloptions,

__insize_tdwinitialsize,

__insize_tdwmaximumsize

); winbaseapi

bool

winapi

heapdestroy(

__inhandlehheap

); winbaseapi

__bcount(dwbytes)

lpvoid

winapi

heapalloc(

__inhandlehheap,

__indworddwflags,

__insize_tdwbytes

); winbaseapi

bool

winapi

heapfree(

__inouthandlehheap,

__indworddwflags,

__dereflpvoidlpmem

); winbaseapi

size_t

winapi

heapsize(

__inhandlehheap,

__indworddwflags,

__inlpcvoidlpmem

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

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

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

初始化

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

zend_apizend_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)elseif(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中為...