Home >Backend Development >PHP Tutorial >Examples of low memory utilization and weak types of PHP arrays

Examples of low memory utilization and weak types of PHP arrays

黄舟
黄舟Original
2017-08-10 10:19:111104browse

This article mainly introduces the detailed interpretation of low memory utilization and weak types of PHP arrays. It has certain reference value and interested friends can refer to it.

The tasks of these two days are completed ahead of schedule. You can take a breath and settle down, and learn PHP in depth. In fact, I originally wanted to learn about PHP performance optimization, but I was shocked by a sentence on the Internet: "PHP array memory utilization is low. A 100MB memory array in C language requires 1G in PHP." Does PHP really consume so much memory? So I took this opportunity to learn about PHP's data type implementation.

Let’s do a test first:


<?php 
  echo memory_get_usage() , &#39;<br>&#39;; 
  $start = memory_get_usage(); 
  $a = Array(); 
  for ($i=0; $i<1000; $i++) { 
   $a[$i] = $i + $i; 
  } 
  $end = memory_get_usage(); 
  echo memory_get_usage() , &#39;<br>&#39;; 
  echo &#39;argv:&#39;, ($end - $start)/1000 ,&#39;bytes&#39; , &#39;<br>&#39;;

The result obtained:

353352
437848
argv: 84.416bytes

An integer array of 1000 elements consumes (437848 - 353352) bytes of memory, which is approximately 82KB, which means that each element occupies 84 bytes of memory. In C language, an int occupies 4 bytes, which is a 20-fold difference overall.

But it is said on the Internet that the results returned by memory_get_usage() are not all occupied by arrays, but also include some structures of PHP itself. Therefore, try another way and use PHP built-in functions to generate arrays:


<?php 
  $start = memory_get_usage(); 
  $a = array_fill(0, 10000, 1); 
  $end = memory_get_usage(); //10k elements array; 
  echo &#39;argv:&#39;, ($end - $start )/10000,&#39;byte&#39; , &#39;<br>&#39;;

The output is:

argv:54.5792byte

is slightly better than just now, but it is still 54 bytes, which is indeed 10 worse. About times.

The reason has to start with the underlying implementation of PHP. PHP is a weakly typed language, regardless of int, double, string, etc., a unified '$' can solve all problems. The bottom layer of PHP is implemented in C language. Each variable corresponds to a zval structure, which is defined in detail as:


typedef struct _zval_struct zval; 
struct _zval_struct { 
  /* Variable information */ 
  zvalue_value value;   /* The value 1 12字节(32位机是12,64位机需要8+4+4=16) */ 
  zend_uint refcount__gc; /* The number of references to this value (for GC) 4字节 */ 
  zend_uchar type;    /* The active type 1字节*/ 
  zend_uchar is_ref__gc; /* Whether this value is a reference (&) 1字节*/ 
};

PHP uses the union structure to store the value of the variable, zvalue_value in zval The value variable of the type is a union, defined as follows:


typedef union _zvalue_value { 
  long lval;         /* long value */ 
  double dval;        /* double value */ 
  struct {          /* string value */ 
    char *val; 
    int len; 
  } str;  
  HashTable *ht;       /* hash table value */ 
  zend_object_value obj;   /*object value */ 
} zvalue_value;

The size of the memory occupied by the union type is determined by the data space occupied by its largest member. In zvalue_value, the int of the str structure occupies 4 bytes and the char pointer occupies 4 bytes, so the memory occupied by the entire zvalue_value is 8 bytes.

The size of zval is 8 + 4 + 1 + 1 = 14 bytes.

Notice that there is also a HashTable in zvalue_value. What does it do? In zval, arrays, strings and objects also require additional storage structures. The storage structure of arrays is HashTable.

The definition of HashTable is given:


typedef struct _hashtable { 
   uint nTableSize; //表长度,并非元素个数 
   uint nTableMask;//表的掩码,始终等于nTableSize-1 
   uint nNumOfElements;//存储的元素个数 
   ulong nNextFreeElement;//指向下一个空的元素位置 
   Bucket *pInternalPointer;//foreach循环时,用来记录当前遍历到的元素位置 
   Bucket *pListHead; 
   Bucket *pListTail; 
   Bucket **arBuckets;//存储的元素数组 
   dtor_func_t pDestructor;//析构函数 
   zend_bool persistent;//是否持久保存。从这可以发现,PHP数组是可以实现持久保存在内存中的,而无需每次请求都重新加载。 
   unsigned char nApplyCount; 
   zend_bool bApplyProtection; 
} HashTable;

In addition to several attribute variables that record the size of the table and the number of elements it contains, Bucket has been used multiple times When used, how Bucket is defined:


typedef struct bucket { 
   ulong h; //数组索引 
   uint nKeyLength; //字符串索引的长度 
   void *pData; //实际数据的存储地址 
   void *pDataPtr; //引入的数据存储地址 
   struct bucket *pListNext; 
   struct bucket *pListLast; 
   struct bucket *pNext; //双向链表的下一个元素的地址 
   struct bucket *pLast;//双向链表的下一个元素地址 
   char arKey[1]; /* Must be last element */ 
} Bucket;

is a bit like a linked list. Bucket is like a linked list node with specific data and pointers, and HashTable is an array. , holds a string of Bucket elements. The implementation of multi-dimensional arrays in PHP is just another HashTable stored in the Bucket.

Calculate that HashTable takes up 39 bytes and Bucket takes up 33 bytes. An empty array takes up 14 + 39 + 33 = 86 bytes. The Bucket structure requires 33 bytes, and the part with a key length longer than four bytes is appended to the Bucket, and the element value is likely to be a zval structure. In addition, each array will be allocated a Bucket pointer array pointed to by arBuckets, although it cannot be said Each additional element requires a pointer, but the situation could be worse. This calculates that one array element will occupy 54 bytes, which is almost the same as the above estimate.

From a space perspective, the average cost of small arrays is larger. Of course, a script will not be filled with a large number of small arrays, and you can gain programming convenience at a smaller space cost. . But if you use an array as a container, it's a different story. In practical applications, you often encounter multi-dimensional arrays with many elements. For example, a one-dimensional array of 10k elements consumes approximately 540k of memory, while a two-dimensional array of 10k The array actually consumes 23M. Small arrays are really not worth it.

The above is the detailed content of Examples of low memory utilization and weak types of PHP arrays. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn