The memory management mechanism of PHP is quite detailed, and it is more similar to the Java garbage collection mechanism at this point. And for C language or C + + Most of the time can only be the programmer himself to the application space release. In PHP, because of the tens of thousands of connections to deal with, these connections often need to be maintained for a long time. This is not the same as when the program ends in C and the corresponding memory block is recycled.
So just rely on programmers to note that memory recycling is not enough, PHP must have their own internal, connection-related memory management mechanism to ensure that no memory leaks.
In this article, we first introduce the memory mechanism of PHP:
The space functions in C language, such as malloc () free () StrDup () realloc () calloc (), are in different forms in PHP.
return the requested memory: for programmers, each piece of application memory should be returned, if not it will lead to memory leaks. In programs that do not require running, a slight memory leak ends after the entire process has been killed. But like Apache, a running Web server, a small memory leak can eventually cause a program to crash.
Examples of error handling :
In the error handling, the mechanism used is generally Zend engine will set a pop-up address, once the exit or die or any serious error e_error, you will use a longjmp () jump to this address. But this approach almost always leads to a memory leak. Because the free operation will be jumped off. (This problem also exists in C + +, when designing a class, you should never write error handling or alarm functions in a construction or destructor function, for the same reason that any error function processing can interrupt this process, possibly resulting in a memory leak, because the object is already at the stage of destruction or creation. This example is given in the following code:
<span style= "Font-family:simsun;"
>void call_function (const char *fname, int fname_len tsrmls_dc) {zend_function *fe;
Char *lcase_fname; /* PHP function names are case-insensitive to simplify locating them in the function tables all function names are Implici tly * translated to lowercase * * lcase_fname = Estrndup (fname, Fname_len);//Create a copy of the function name Zend_str_tolower (
Lcase_fname, Fname_len);//all converted to lowercase, such a search is convenient, this should also be in the PHP function table in the way of function identification. if (Zend_hash_find (EG (function_table), Lcase_fname, Fname_len + 1, (void * *) &fe) = = failure) {. SUCCESS.
This is to find the function to be called in the function table.
Zend_execute (Fe->op_array tsrmls_cc); else {php_error_docref (NULL tsrmls_cc, E_error, "call to undefined function:%s" ( ) ", fname);
Equivalent to Trigger_error ()} efree (Lcase_fname); }</span>
In this example, a PHP function is provided when calling a function. When PHP calls a function, it needs to go to the function table, which is function_table, to find the appropriate function, and to convert it to a lowercase letter before looking for it, which can improve the search efficiency. By using the Zend_hash_find function, if a function is found to be called, it is invoked with Zend_execute. And if not found haunted will jump out of the error, show did not find. But here's the problem, notice. A lowercase version of the function name string was created in order to find the function. This string until the Zend_hash_find function is used, once the error has not been found, then the corresponding memory space of the string must not be found back, which caused the leak of memory.
Therefore, PHP provides a
Zend Memory Management, Zend memory management also known as ZENDMM.
Memory Management in PHP is similar to the operating system mechanism, but the object is the memory involved in each request. In addition ZENDMM will also control the INI file in the provisions of the memory_limit, that is, once each request requires more memory than the memory limit, it will also apply for failure. At the bottom of the diagram, you see the layer that is associated with the operating system. For standard memory request and release methods in the operating system, PHP has a corresponding function. These functions are not a simple replacement, they contain specific information that, with the help of this information, can identify the blocks of memory that each request is requesting. This enables separate management of the memory area for each request. At the same time, see a total of two kinds of memory requests in the diagram: Persistent and per-request, for persistent is almost the same as the system request, that is, independent of each request, will not be recycled after the request is completed. But sometimes persistent may be runtime to know, so in this case, a flag is needed to indicate this. The way in which memory requests are made is different for persistent. The corresponding relationship is given below: Pemalloc (buffer_len,1) = = malloc (buffer_len) permalloc (buffer_len,0) = = Emalloc (Buffer_len) This connection is determined by the way that the macro is defined #define PEMALLOC (size,persistent) \ (persistent)? malloc (size): Emalloc (size) flag=1 says it is persistent, 0 is not, It is the same as the general Emalloc of the request.
The following figure allows you to see a comparison of the system's memory request function with the memory request function in PHP:
If you are not familiar with the functions of malloc, calloc and realloc, please go to: http://www.cppblog.com/sandywin/archive/2011/09/14/155746.html
In addition, there are two
memory functions in Safe Mode: void *safe_emalloc (size_t size, size_t count, size_t ADDTL);
void *safe_pemalloc (size_t size, size_t count, size_t Addtl, char persistent); The space they are applying for is Size*count + ADDTL, the reason for this is to avoid an int type overflow.
Next, let's say a more interesting, PHP
Reference Count:
There are references in many languages, and many times they use references. You can save space by referencing, because sometimes it is not necessary to make a copy of each variable. Reference counting refers to how many variables are referenced by the same memory space, thus avoiding possible memory error operations. First look at the following code:
* {
* zval *helloval;
* Make_std_zval (helloval);
* zval_string (helloval, "Hello World", 1);
* Zend_hash_add (EG (active_symbol_table), "a", sizeof ("a"),
* &helloval, sizeof (zval*), NULL);
* Zend_hash_add (EG (active_symbol_table), "B", sizeof ("B"),
* &helloval, sizeof (zval*), NULL);
* }
The code first declares a zval variable, initializes it with a make_std_zval, and then uses zval_string to attach the initial value. Then for this variable, give the two variable names. The first one is a, the second is B, there is no doubt that the second one is definitely a reference. But this code must have a problem, the problem is that you do not update the corresponding reference count after using the Zend_hash_add. Zend does not know that you have added such a reference, which results in the release of memory may result in two releases. So the correct code after the modification is as follows:
* {
* zval *helloval;
* Make_std_zval (helloval);
* zval_string (helloval, "Hello World", 1);
* Zend_hash_add (EG (active_symbol_table), "a", sizeof ("a"),
* &helloval, sizeof (zval*), NULL);
* <strong>zval_addref (helloval); </strong>//Plus this, there's no way to recreate the same memory space.
* Zend_hash _add (EG (active_symbol_table), "B", sizeof ("B"),
* &helloval, sizeof (zval*), NULL);
* }
After the zval_addref is done, the next time unset the variable, the Ref_count reference count is viewed first, and if the =1 is released, if the >1 is only-1, no memory release is performed.
Copy on WriteLet's look at the following section of PHP code:
<?php
$a = 1;
$b = $a;
$b + 5;
? >
Obviously in the second line, B declares a reference to a A, then after executing the third line of code, b increases, and a does not increase. Many times may not want to increase. So this time when Zend detects the refcount>1, it performs a variable-detach operation that turns the original piece of memory into two pieces of memory:
Zval *get_var_and_separate (char *varname, int varname_len tsrmls_dc) {zval **varval, *varcopy; if (Zend_hash_find (EG active_symbol_table), varname, Varname_len + 1, (void**) &varval) = = Failu
RE) {//return NULL not found in the/* symbol table;
The If ((*varval)->refcount < 2) {/* varname is the only reference, nothing to do without doing */return *varval;
}/* Otherwise, not the only reference, give zval* a copy * * * Make_std_zval (varcopy);
Varcopy = *varval; /* Duplicate Any allocated structures within the zval*/Zval_copy_ctor (varcopy); How this piece is copied. Mark should have been connected to Varval's varname./* Delete the varname version, which will reduce the number of varval citations * * Zend_hash_del (EG (active_symbol_table), Varnam
E, Varname_len + 1);
/* Initialize the number of references to the newly created value, and then attach to the varname variable */varcopy->refcount = 1;
Varcopy->is_ref = 0; Zend_hash_add (EG (active_symbol_table), varname, Varname_len + 1, &varcopy, siz
EOF (zval*), NULL);
* * Return the new zval* * * return varcopy; }
First see the two judgments, the first judgment statement in the symbol table to see if the corresponding variable, if not found there is no need to separate. The second judgment statement is to see if the number of references to the input variable is less than 2, and if so, the input variable *varval is unique and does not need to be separated. Otherwise, there must be a reference, this time to make a copy of Varcopy. This copy will inherit VarName's corresponding value, but the difference is to help it reapply the memory space, reinitialize the refcount and Is_ref parameters. Take A, B as an example, in $b+=5, after the execution, B as varname to find out whether there is a reference, found that there is a reference to a, this time the value of B, and then reapply for a space, in re-register to B. In this case, there are two separate blocks of memory.
Change on WriteLook at one more piece of code:
<?php
$a = 1;//After executing this sentence, the ref_count of a variable is 1,is_ref 0
$b = & $a;//After this sentence, the zval* of the variable (ref_count) is 2, and then because of the display &,is_ref is 1
$b + + 5;//This time there will be no separation in the execution of this sentence
?>
If you feel that you want a to change with B, there is no problem, as long as you explicitly use the & symbol to quote the statement. In that case, the IS_REF flag will be placed 1. There is no need to separate the memory blocks at this time. So in the above code you have to change the judgment of the second if statement:
if ((*varval)->is_ref | | (*varval)->refcount < 2) {/*
varname is the only actual reference,
* or it's a full reference to other Vari Ables
* Either way:no separating to being done
/return *varval;
In the last case, the situation is most troubling:
<?php
$a = 1;
$b = $a;
$c = & $a;
? >
Neither copy on write nor change on Wirte, there is no way, but to separate. Here's the B-Independent:
Some of the mechanisms for PHP memory management here, it feels like PHP is really a pretty amazing language. Ha ha.
Original link http://meijing0114.com/2014/12/13/2/