ホームページ  >  記事  >  バックエンド開発  >  PHP 配列の低メモリ使用率の詳細な分析

PHP 配列の低メモリ使用率の詳細な分析

小云云
小云云オリジナル
2018-01-30 10:11:361694ブラウズ

PHP は本当に多くのメモリを消費しますか?そこで私はこの機会を利用して、PHP のデータ型の実装について学びました。この記事では主に、PHP 配列の低メモリ使用率と弱い型の詳細な解釈を紹介します。一定の参考値があるので、興味のある方は参考にしてください。

まずテストをしてみましょう:


<?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;;

結果:

353352
437848
argv: 84.416bytes

1000 要素の整数配列はメモリを消費します (4 37848 - 353352) バイト、約 82KB 、つまり各要素は 84 バイトのメモリを占有します。 C 言語では、int は 4 バイトを占有し、全体で 20 倍の違いがあります。

しかし、インターネットでは、memory_get_usage() によって返される結果はすべての配列占有ではなく、PHP 自体の構造も含まれていると言われています。そのため、別の方法を試し、PHP 組み込み関数を使用して配列を生成してください。


<?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;;

出力は次のとおりです:

argv:54.5792byte


は以前よりわずかに改善されましたが、それでも 54 バイトであり、確かに約 10 倍悪くなります。


その理由は、基礎となる PHP の実装から始まる必要があります。 PHP は型付けが弱い言語ですが、int、double、string などに関係なく、統一された '$' ですべての問題を解決できます。 PHP の最下層は C 言語で実装されており、各変数は zval 構造体に対応しており、その詳細な定義は次のとおりです。


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 は、zvalue_value 型の value 変数を使用して変数の値を格納します。 zval は共用体であり、次のように定義されます:


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;

共用体型によって占有されるメモリのサイズは、その最大のメンバーによって占有されるデータ領域によって決まります。 zvalue_value では、str 構造体の int が 4 バイト、char ポインタが 4 バイトを占めるため、zvalue_value 全体が占めるメモリは 8 バイトになります。


zvalのサイズは8 + 4 + 1 + 1 = 14バイトです。


zvalue_value にも HashTable があることに注意してください。これは何をするのでしょうか? zval では、配列、文​​字列、オブジェクトにも追加のストレージ構造が必要です。配列のストレージ構造は HashTable です。


HashTable の定義は次のとおりです:


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;

テーブルのサイズとそれに含まれる要素の数を記録するいくつかの属性変数に加えて、Bucket の定義方法:


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;

リンク リストと少し似ています。Bucket は特定のデータとポインターを含むリンク リスト ノードのようなもので、HashTable は Bucket 要素の文字列を格納する配列です。 PHP での多次元配列の実装は、バケットに格納される別の HashTable にすぎません。


HashTable が 39 バイト、Bucket が 33 バイトを占めることを計算します。空の配列は 14 + 39 + 33 = 86 バイトを占めます。 Bucket 構造体には 33 バイトが必要で、キー長が 4 バイトを超える部分は Bucket の末尾に追加され、要素の値は zval 構造体になる可能性が高く、さらに各配列には Bucket ポインターが割り当てられます。 arBuckets が指す配列。ただし、追加要素ごとにポインタが必要であるとは言えませんが、状況はさらに悪化する可能性があります。これは、1 つの配列要素が 54 バイトを占有することを計算し、これは上記の見積もりとほぼ同じです。


スペースの観点から見ると、小さな配列は平均してコストが高くなります。もちろん、スクリプトが多数の小さな配列で埋め尽くされることはなく、より少ないスペース コストでプログラミング速度を向上させることができます。しかし、配列をコンテナとして使用する場合は別の話になります。実際のアプリケーションでは、多くの要素を含む多次元配列が頻繁に発生します。たとえば、10k 要素の 1 次元配列は約 540k のメモリを消費しますが、10k の 2 次元配列は実際には 23M を消費します。小さな配列には実際には価値がありません。


PHP 配列のメモリ使用率が低い理由については、次の記事で説明します。


関連する推奨事項:


PHP 配列がメモリを過剰に消費する問題の解決策_PHP チュートリアル

PHP 配列がメモリを過剰に消費する問題の解決策

PHP 配列が過剰に消費する問題の解決策メモリが多い Method_php のヒント

以上がPHP 配列の低メモリ使用率の詳細な分析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。