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

PHP 配列のメモリ使用量の分析

藏色散人
藏色散人転載
2019-12-09 17:54:092309ブラウズ

次のアプローチではどれくらいのメモリが必要になりますか?

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 サイトの他の関連記事を参照してください。

声明:
この記事はsegmentfault.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。