PHP Kernel exploration variables (1) zval

Source: Internet
Author: User
Tags learn php scalar

As a container of data, we often need to deal with variables, whether the variable is a number, an array, a string, an object, or something else, so that variables can be used as an indispensable basis for language formation. This article is the first of the variables of PHP kernel exploration, mainly introduces the basic knowledge of zval, including the following aspects:

    1. The basic structure of zval
    2. Ways to view Zval: Debug_zval_dump and Xdebug
    3. The principle of zval, cow, etc.

Due to the hasty writing, there will inevitably be mistakes, welcome to point out.

first, the basic structure of Zval

Zval is one of the most important data structures in PHP (another important data structure is hash table), which contains information about variable values and types in PHP. It is a struct, and the basic structure is:

struct _zval_struct {    zvalue_value value;      /*  */    zend_uint refcount__gc  ; /*  */    zend_uchar type          ; /*  */    zend_uchar is_ref__gc    ; /*  */struct _zval_struct zval;

which

1. Zval_value value

The actual value of the variable, specifically a Zvalue_value Union (union):

typedef Union _ZVALUE_VALUE {LongLval;/*Long Value*/    DoubleDval;/*Double Value*/    struct{/*string*/        Char*Val; intLen;    } str; HashTable*HT;/*Hash table value,used for array*/Zend_object_value obj; /*Object*/} zvalue_value;

2. Zend_uint refcount__gc

The value is actually a counter that is used to hold how many variables (or symbols,symbols, all symbols exist in the symbol table (symble table), different scopes use different symbol tables, and for this we will discuss later) point to the Zval. When a variable is generated, its refcount=1, a typical assignment operation such as $ A = $b will add 1 to the Zval RefCount, and the unset operation will be reduced by 1 accordingly. Before PHP5.3, using the mechanism of reference counting to implement GC, if a zval refcount less than 0, then the Zend engine will assume that there is no variable pointing to the Zval, thus releasing the memory space occupied by the Zval. But things are not that simple at times. In the following we will see that the simple reference counting mechanism cannot GC out the zval of the circular reference, even if the variable pointing to the Zval has been unset, resulting in a memory leak (memoriesLeak).

3. Zend_uchar type

This field is used to indicate the actual type of the variable. When we started to learn PHP, we already knew that variables in PHP included four scalar types (bool,int,float,string), two composite types (Array, object), and two special types (Resource and null). Within Zend, these types correspond to the following macro (code location PHPSRC/ZEND/ZEND.H):

#define Is_null     0#define is_long     1#define is_double   2#define is_bool     3# Define Is_array    4#define is_object   5#define is_string   6#define Is_resource 7#define is_constant 8#define is_constant_array   9#define is _callable 10

4. IS_REF__GC

This field is used to mark whether a variable is a reference variable. For a normal variable, the value is 0, and for a reference-type variable, the value is 1. This variable affects zval sharing, separation, and so on. We will discuss this later.

As the name suggests, REF_COUNT__GC and is_ref__gc are important two fields that are required by the PHP GC mechanism, and the values of these two fields can be viewed by debugging tools such as Xdebug.

second, the installation configuration of Xdebug

Xdebug is an open source PHP performance analysis and Debug tool. Although common debugging tools for general program debugging,var_dump,echo,print, debug_backtrace, etc., are basically adequate, but for some complex debugging and performance testing, Xdebug is definitely a good helper (other tools such as Xhprof are also excellent).

The basic environment of this article:

The basic process for installing xdebug is (actually, the source code compiles an extension):

1. Download the source package.

is: Http://www.xdebug.org/docs/install

The version that is downloaded in this article is: xdebug-2.6.tar.gz

2. Unzip

tar xvzf xdebug-2.6. tar. gz

3. Execution of phpize in Xdebug directory

4../configure Configuration

5. make&& make Install

This generates xdebug.so extension files (zend_extension), located in Xdebug/modules

6. Load the xdebug extension in php.ini

Zend_extension=your-xdebug-path/xdebug.so

7. Add the Xdebug configuration

xdebug.profiler_enable == Onxdebug.trace_output_dir= "/tmp/xdebug"= trace.%c.% Pxdebug.profiler_output_dir= "/tmp/xdebug"xdebug.profiler_output_name= "cachegrind.out.%s"

There is no longer a detailed description of the meanings of each configuration item, see: Http://www.xdebug.org/docs/all

Now, PHP, you should already have Xdebug extension information (php–m, or Phpinfo ()):


Now, in your script, you can print zval information by Xdebug_debug_zval:

$a = array (' Test '), $a [] = & $a; Xdebug_debug_zval (' a ');
3. More Principles of Zval

(note, this section main reference: http://derickrethans.nl/collecting-garbage-phps-take-on-variables.html, author Derick Rethans is an excellent PHP kernel expert , has done many reports in the world, all have the relevant PDF download, here (http://derickrethans.nl/talks.html) has the author each speech record, many are worth our thorough study study)

As we have said earlier, PHP uses zval structure to save variables, and here we will continue to track more details of Zval.

1. When creating a variable, a zval is created.

$STR = "Test Zval"; Xdebug_debug_zval (' str ');

Output Result:

STR: (refcount=1, is_ref=0) = ' Test Zval '

When using $str= "Test Zval", to create a variable, a new symbol (STR) is inserted in the symbol table of the current scope, because the variable is a normal variable and therefore generates a refcount=1 and is_ref=0 The Zval container. In other words, this is actually the case:

2. When assigning a variable to another variable, the RefCount value of zval is increased.

$str  = "Test Zval"; $str 2 = $str; Xdebug_debug_zval (' str '); Xdebug_debug_zval (' str2 ');

Output Result:

STR: (refcount=2, is_ref=0) =' Test zval ' str2: (refcount=2, is_ref=0) = ' Test Zval '

At the same time we see that STR is the same as the zval structure of the two symbol STR2. This is actually a PHP optimization, because STR and str2 are common variables, so they point to the same zval, but not for STR2 open a separate zval. In doing so, you can save memory to some extent. The correspondence between the STR,STR2 and the Zval is as follows:

3. When using unset, reduce the refcount value of the corresponding Zval
$str  = "Test Zval"; $str 3 = $str 2 = $str; Xdebug_debug_zval (' str '); unset ($str 2, $str 3) xdebug_debug_zval (' str ');

The result is:

STR: (refcount=3, is_ref=0) =' Test zval ' str: (RefCount=1, is_ref=0) = ' Test Zval '

Because Unset ($str 2, $str 3) removes str2 and str3 from the symbol table, after unset, only str points to the Zval, as shown in:

Now if unset ($STR) is executed, the zval is scavenged from memory because the refcount of Zval is reduced to 0. This is, of course, the ideal situation.

But things aren't always that optimistic.

4. Array variables are very similar to the zval generated by ordinary variables, but they are also very different

Unlike scalar these common variables, variables such as arrays and objects, when generating zval, generate a Zval container for each item item. For example:

1234 $ar= array(    ‘id‘=> 38,    ‘name‘=> ‘shine‘); <br><span style="font-size: 14px;">xdebug_debug_zval(‘ar‘);</span>

The structure to print out the Zval is:

AR: (refcount=1, is_ref=0) =Array (    = = (Refcount=1, is_ref=0) =38     , = = (Refcount=1, is_ ref=0) =' shine ')

As shown in the following:

As you can see, a total of 3 zval containers (highlighted in red) were generated during the generation of the variable $ar. For each zval, the refcount and increment rules are the same as the normal variables. For example, we add another element to the array and assign the value of $ar[' name '] to it:

$ar = Array (    ' id ' = ' = '   ,    ' name ' = ' shine '); $ar [' test '] = $ar [' Name '];xdebug_debug_zval (' ar ');

The printed zval is:

AR: (refcount=1, is_ref=0) =Array (    = = (Refcount=1, is_ref=0) =38    , = = (refcount=2, is_ ref=0) = ' shine ',    = = (refcount=2, is_ref=0) =' shine ')

As with normal variables, the two symbol name and test point to the same zval:

Similarly, when an element is removed from an array, the corresponding symbol is removed from the symbol table and the RefCount value of the corresponding Zval is reduced. Similarly, if the RefCount value of Zval is reduced to 0, the zval is removed from memory:

$ar = Array (    ' id ' = ' = '   , '    name ' = ' shine '); $ar [' test '] = $ar [' Name '];unset ($ar [' Test '], $ar [' Name ']); Xdebug_debug_zval (' ar ');

The output is:

AR: (refcount=1, is_ref=0) =array (' id ' = = (Refcount=1, is_ref=0) =38)

5. The advent of references complicates the Zval rules

After adding a reference, the situation becomes slightly more complicated. For example, add a reference to itself in the array:

$a = $array (' one '), $a [] = & $a; Xdebug_debug_zval (' a ');

Results of the output:

A: (refcount=2, is_ref=1) =Array (    0 = (refcount=1, is_ref=0) = ' One ',     1 = (refcount=2, is_ref=1) =...)

The above output, ... Represents a reference to the original array, so this is a circular one. As shown in the following:

Now we perform a unset operation on $ A, which removes the corresponding symbol in the symbol table, while the Zval RefCount minus 1 (before 2), that is, the current zval should be such a structure:

(Refcount=1, is_ref=1) =Array (    0 = (refcount=1, is_ref=0) = ' One ',     1 = (refcount=1, is_ref=1) = ...)

This is the structure shown:

At this time, the unfortunate thing happened!

After unset, although no variable points to the Zval, the zval cannot be cleaned up by GC (referred to as the GC of the simple reference counting mechanism before PHP5.3), since Zval RefCount are greater than 0. In this way, these zval will actually persist in memory until the request is over (refer to the SAPI lifecycle). Until then, the memory that these zval occupy cannot be used and wasted, in other words, the memory that cannot be freed causes a memory leak.

If this memory leak happened only once or a few times, it would be fine, but if it were thousands of memory leaks, it would be a big problem. Especially in long-running scripts (such as daemons, which do not break in the background), because the memory cannot be reclaimed, it will eventually cause the system to "no more memory available".

6. Zval Separation (Copy on write and change on write)

As we have described earlier, in the process of assigning values to variables such as $b = $a, in order to save space, it does not open a separate zval for $ A and $b, but instead uses the form of shared zval:

So the question is: How do you deal with zval sharing issues if one of the variables changes?

For such a code:

$a = "a simple test"; $b = $a; echo "Before write:". Php_eol;xdebug_debug_zval (' a '); Xdebug_debug_zval (' B '); $b = "THSS"; echo "after write:". Php_eol;xdebug_debug_zval (' a '); Xdebug_debug_zval (' B ');

The result of the printing is:

before Write:a: (RefCount=2, is_ref=0) =' A simple test ' B: (RefCount=2, is_ref=0) =' A simple test ' After Write:a: (RefCount=1, is_ref=0) =' A simple test ' B: (RefCount=1, is_ref=0) = ' THSS '

At first, A and B in the symbol table point to the same zval (the reason for this is to save memory), and then $b changes, Zend checks if the refcount of the Zval to B is 1, if it is 1, then only one symbol points to the Zval, the zval is changed directly. Otherwise, it is a shared zval that needs to separate the zval to ensure that individual changes are not affected, and this mechanism is called COW –Copy on write. In many scenarios, cow is a more efficient strategy.

So what about reference variables?

$a = ' Test '; $b = & $a; <br>echo "before Change:". Php_eol;xdebug_debug_zval (' a '); Xdebug_debug_zval (' B ');<br> $b = 12;echo "after change:". Php_eol;xdebug_debug_zval (' a '); Xdebug_debug_zval (' B '); <br>unset ($b); echo "after unset:". Php_eol;xdebug_debug_zval (' a '); Xdebug_debug_zval (' B ');

The result of the output is:

before Change:a: (RefCount=2, is_ref=1) =' Test ' B: (RefCount=2, is_ref=1) =' Test ' after Change:a: ( RefCount=2, is_ref=1) =12B: (RefCount=2, is_ref=1) =12 afterunset:a: (refcount=1, is_ref=0) =12

As you can see, after changing the value of the $b, Zend checks whether the Is_ref check of the zval is a reference variable, and if it is a reference variable, it is changed directly, otherwise the zval separation that is just mentioned needs to be performed. Because $ A and $b are reference variables, changing the shared zval actually indirectly changes the value of $ A. After unset ($b), the variable $b is removed from the symbol table.

This also illustrates a problem where unset does not clear zval, but only removes the corresponding symbol from the symbol table. As a result, many of the previous questions about references are understandable (we'll delve into PHP's references in the next section).

This article refers to the literature:
    1. Brother Bird's in-depth variable reference/detach http://www.laruence.com/2008/09/19/520.html
    2. The main references in this paper are http://derickrethans.nl/collecting-garbage-phps-take-on-variables.html
    3. http://blog.csdn.net/phpkernel/article/details/5732784
    4. Http://www.jb51.net/article/50080.htm
    5. http://www.nowamagic.net/librarys/veda/detail/1442

PHP Kernel Explorer variable (1) Zval

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.