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