次のアプローチではどれくらいのメモリが必要になりますか?
list($appid,$openid) = ["testcontent","test"];
Test
$m0 = memory_get_usage(); $k = range(1,200000); $m1 = memory_get_usage(); echo round(($m1-$m0)/pow(1024,2),4) ."MB\n"; foreach ($k as $i){ $n1 = "kk$i"; $n2 = "tt$i"; list($$n1,$$n2) = [$i,$i*3]; } $m2 = memory_get_usage(); echo round(($m2-$m1)/pow(1024,2),4) ."MB\n"; $m1 = memory_get_usage(); foreach ($k as $i){ $n1 = "kk$i"; $n2 = "tt$i"; $$n1 = $i+time(); $$n2 = 2*time(); } $m2 = memory_get_usage(); echo round(($m2-$m1)/pow(1024,2),4) ."MB\n";
上記の演算出力の結果は次のとおりです:
27.9404MB 51.3041MB 9.1553MB
メモリが配列によって占有されていることがわかります。通常割り当てられるコンテンツよりもはるかに大きいです
原則
PHP では、数値を表すために long 型が使用され、int 型は使用されません。 PHP が弱い型指定言語であることは誰もが理解していますが、変数の型を区別せず、int float char * などの概念がありません。 PHP が zend に保存する変数を見てみましょう。PHP の各変数には、対応する zval があります。Zval 構造は Zend/zend.h で定義されています。その構造:
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 は UNION 構造を使用して保存します変数の値、つまり zvalue_value は共用体です。UNION 変数が占有するメモリは、最大メンバー データ スペースによって決まります。
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;
最大のメンバー データ スペースは struct str で、ポインターは *val に 4 バイト、INT は 4 バイト、合計 8 バイトを占めます。
構造体 zval が占めるスペースは 8 4 1 1 = 14 バイトです。実際、zval 内の配列、文字列、オブジェクトには追加のストレージ構造が必要です。配列はハッシュテーブルです:
ハッシュテーブル構造体は Zend/zend_hash.h で定義されています。
typedef struct _hashtable { uint nTableSize;//4 uint nTableMask;//4 uint nNumOfElements;//4 ulong nNextFreeElement;//4 Bucket *pInternalPointer; /* Used for element traversal 4*/ Bucket *pListHead;//4 Bucket *pListTail;//4 Bucket **arBuckets;//4 dtor_func_t pDestructor;//4 zend_bool persistent;//1 unsigned char nApplyCount;//1 zend_bool bApplyProtection;//1 #if ZEND_DEBUG int inconsistent;//4 #endif } HashTable;
HashTable 構造体には 39 バイトが必要で、各配列要素は Bucket 構造体に格納されます。
typedef struct bucket { ulong h; /* Used for numeric indexing 4字节 */ uint nKeyLength; /* The length of the key (for string keys) 4字节 */ void *pData; /* 4字节*/ void *pDataPtr; /* 4字节*/ struct bucket *pListNext; /* PHP arrays are ordered. This gives the next element in that order4字节*/ struct bucket *pListLast; /* and this gives the previous element 4字节 */ struct bucket *pNext; /* The next element in this (doubly) linked list 4字节*/ struct bucket *pLast; /* The previous element in this (doubly) linked list 4字节*/ char arKey[1]; /* Must be last element 1字节*/ } Bucket;
Bucket 構造体には 33 バイトが必要です。 Bucket の末尾にキー長が 4 バイトを超える部分が追加され、要素の値が zval 構造体になる可能性が高く、また、各配列には arBuckets が指す Bucket ポインタの配列が割り当てられますが、これは割り当てられません。要素が追加されるたびにポインターが必要になると言われていますが、状況はさらに悪化する可能性があります。これは、1 つの配列要素が 54 バイトを占有することを計算し、これは上記の見積もりとほぼ同じです。
空の配列は、少なくとも 14(zval) 39(HashTable) 33(arBuckets) = 86 バイトを占めます。変数として、シンボル テーブル内に位置が必要であり、配列要素でもあるため、空の配列 配列変数の記述と格納には 118 バイトが必要です。スペースの観点から見ると、小さな配列は平均して高価ですが、もちろん、スクリプトが多数の小さな配列で埋め尽くされることはなく、より少ないスペースコストでプログラミングの利便性が得られます。しかし、配列をコンテナとして使用する場合は別の話になり、実際のアプリケーションでは、多くの要素を含む多次元配列に遭遇することがよくあります。たとえば、10k 要素の 1 次元配列は約 540k のメモリを消費しますが、10k の配列は実際には 23M を消費し、小さな配列には実際には価値がありません。
以上がPHP 配列のメモリ使用量の分析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。