internals:zend_mm

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
internals:zend_mm [2011/11/09 12:15]
laruence
internals:zend_mm [2017/09/22 13:28] (current)
Line 3: Line 3:
   * Date: 2011-11-09   * Date: 2011-11-09
   * Author: Xinchen Hui <laruence@php.net>   * Author: Xinchen Hui <laruence@php.net>
-  * Chinese: http://www.laruence.com/2011/11/09/2277.html+  * Chinese(中文版): http://www.laruence.com/2011/11/09/2277.html
   * First Published at: https://wiki.php.net/internals/zend_mm   * First Published at: https://wiki.php.net/internals/zend_mm
  
 ===== Background ===== ===== Background =====
 <code> <code>
-<laruence_> Felipe, is there any docs about zend mm?   +<laruence> Felipe, is there any docs about zend mm?   
-<Felipe> laruence_: almost nothing... just Zend/README.ZEND_MM +<Felipe> laruence: almost nothing... just Zend/README.ZEND_MM 
 </code> </code>
 So I decided to write one, to describe the whole implement of Zend mm(memory allocating, memory freeing) So I decided to write one, to describe the whole implement of Zend mm(memory allocating, memory freeing)
Line 15: Line 15:
 I am not good at english, so if you find some wrong words, plz feel free to edit it. I am not good at english, so if you find some wrong words, plz feel free to edit it.
 ===== Zend MM ===== ===== Zend MM =====
-Zend mm is the memory manager of PHP,  it apply memory from OS, then allocate the memory to PHP script by emalloc.+PHP is written entirely in C. In C, the programmer is responsible for the allocation and release of memory during runtime
  
-Zend mm divides memory into two type, small memory and large memory+PHP has very specific requirements for management of memory and many modes of execution; all sharing a common set of requirements
  
-for small memory,  Zend mm target at emalloc/efree quickly and also has a cache mechanism for them.+The memory manager in PHPnamed Zend MMfacilitates these requirements in the same way, whatever the mode of execution, whatever the code.
  
-for large memory,  Zend mm is very careful to avoid memory waste. +The memory manager has two distinct types of allocation:
  
 + small: when allocating small blocks of memory, it is important that the manager is fast and efficient. 
 +
 + large: when allocating large blocks of memory, it is important that the manager minimizes wastage.
 +
 +The developer makes allocations that have two distinct life cycles:
 +
 + request: the most common type of allocation made; the developer requires the memory to service the current request
 +
 + persistent: the developer intends to reference the memory in multiple requests
 +
 +The MM provides the following (per request) functions:
 +
 + void*  emalloc(size_t size);
 + void*  erealloc(void* pointer, size_t size);
 + void*  ecalloc(size_t num, size_t count);
 + void   efree(void* pointer);
 +
 +They all share prototype and functionality with the standard C implementation, but the allocation is optimized, and tracked. Tracking allocations allows a margin of error not normally present in C programming: memory that is not free'd explicitly will normally be free'd by the implementation at the appropriate time, such as the end of the request, or the end of execution.
 +
 +Zend provides the following (persistence) functions:
 +
 + void* pemalloc(size_t size, zend_bool persistent);
 + void* perealloc(void* pointer, size_t size, zend_bool persistent);
 + void* pecalloc(size_t num, size_t count, zend_bool persistent);
 + void  pefree(void* pointer, zend_bool persistent);
 +
 +Persistent memory is not optimized, or tracked by the implementation, and should only be used if the developer requires a structure to survive requests.
 +
 +The following diagrams and explanations provide insight into how and why Zend MM manages the per request memory it allocates.
 ===== Struct zend_mm_heap ===== ===== Struct zend_mm_heap =====
 <code c> <code c>
Line 143: Line 172:
 {{:internals:zend_mm_large_buckets.png|}}  {{:internals:zend_mm_large_buckets.png|}} 
  
 +as I said above, that there is a number of ZEND_MM_NUMBER_BUCKET large_free_bucket, and will see that Zend MM use the order of the highest 1 in the true_size of a memory request to determined the index.
 +
 +that means, each item in the large_free_buckets holds the size which with a corresponding index order value 1. 
 +
 +ie:
 +the heap->large_free_buckets[2] holds the pointer of memory block which size is between 0b1000 and 0b1111, and the heap->large_free_buckets[6] holds pointer of memory block which size is between 0b10000000 and 0b11111111.
 ===== zend_mm_heap->rest_buckets ===== ===== zend_mm_heap->rest_buckets =====
  
Line 210: Line 245:
 </code> </code>
 as I said, the large_free_buckets is kind of trie tree, assuming a true_size(b01001010), Zend vm try to find the best_fit by hash the binary value as a 'key'. as I said, the large_free_buckets is kind of trie tree, assuming a true_size(b01001010), Zend vm try to find the best_fit by hash the binary value as a 'key'.
-that is,  Zend MM start from large_free_buckets[index], try to find the best fit size memory for the true size accroding to the each bit of the true_size.+that is,  Zend MM start from large_free_buckets[4], try to find the best fit size memory for the true size accroding to the each bit of the true_size.
 <code c> <code c>
     if (UNEXPECTED((bitmap & 1) != 0)) {     if (UNEXPECTED((bitmap & 1) != 0)) {
Line 267: Line 302:
 let's take the b101010 as a example: let's take the b101010 as a example:
  
-a. first compute the index,  if the memory at the index is exactly  is the same size as true_size, then allocating succeed, and return the block->next_free_buckets.+a. first compute the index,  if the memory block in the large_free_buckets[indexis exactly  is the same size as true_size, then allocating succeed, and return the block->next_free_buckets.
  
-b. look at second bit of the true_size, it's 0, so Zend MM will looking for the best fit in the block->child[0], if the block->child[0] is the same size as true_size, then allocating succeed, return, if not, lookat the third bit of the true_size, it's 1, so Zend MM will do the looking loop in the block->child[1].+b. look at highest(based on index: m = true_size << (ZEND_MM_NUM_BUCKETS - index)) bit of the true_size, it's 0, so Zend MM will looking for the best fit in the block->child[0], if the block->child[0] is the same size as true_size, then allocating succeed, return, if it's 1, Zend MM will do the looking loop in the block->child[1].
  
 c. if the bit is 0, but the block doesn't has a child[0]? Zend MM will try to find the samllest memory under the block->child[1]. c. if the bit is 0, but the block doesn't has a child[0]? Zend MM will try to find the samllest memory under the block->child[1].
  
 d. if the bit is 1, but the block doesn't has a child[1], goto 6.3-B d. if the bit is 1, but the block doesn't has a child[1], goto 6.3-B
 +
 +f. left shift m(which make the next bit in the true_size will be considered in the next loop), and make the current node as child[1] or child[0](described above), then goto a, start a new loop.
  
 6.3-B looking for the smallest "large memory". if found, allocating succeed, and return best_fit->next_free_block. 6.3-B looking for the smallest "large memory". if found, allocating succeed, and return best_fit->next_free_block.
Line 286: Line 323:
 </code> </code>
  
-looking at the (p = p->child[p->child[0] != NULL]), Zend MM is trying to find the "smallest" one.+Note the (p = p->child[p->child[0] != NULL]), Zend MM is trying to find the "smallest" one.
  
 7. search in the rest_buckets, it is a list. used to cache some big size memory before put them into free_buckets, if found allocating succeed, and return 7. search in the rest_buckets, it is a list. used to cache some big size memory before put them into free_buckets, if found allocating succeed, and return
internals/zend_mm.1320840919.txt.gz · Last modified: 2017/09/22 13:28 (external edit)