PHP數組實際佔用記憶體大小的分析

來源:互聯網
上載者:User

http://blog.csdn.net/hguisu/article/details/7376705

我們在前面的php高效寫法提到,盡量不要複製變數,特別是數組。一般來說,PHP數組的記憶體利用率只有 1/10, 也就是說,一個在C語言裡面100M 記憶體的數組,在PHP裡面就要1G。下面我們可以粗略的估算PHP數組佔用記憶體的大小,首先我們測試1000個元素的整數佔用的記憶體:

<?php      echo memory_get_usage() , '<br>';      $start = memory_get_usage();      $a = Array();      for ($i=0; $i<1000; $i++) {      $a[$i] = $i + $i;      }      $mid =  memory_get_usage();      echo memory_get_usage() , '<br>';      for ($i=1000; $i<2000; $i++) {      $a[$i] = $i + $i;      }      $end =  memory_get_usage();      echo memory_get_usage() , '<br>';      echo 'argv:', ($mid - $start)/1024 ,'kb' , '<br>';      echo 'argv:',($end - $mid)/1024 ,'kb' , '<br>';  

輸出是:

350752
435248
519424
argv:84.416byte
argv:84.176byte

大概瞭解1000 個元素的整數數組需要佔用 82k 記憶體,平均每個元素佔用 84 個位元組。而純 C 中整體只需要 4k(一個整型佔用4byte * 1000 )。memory_get_usage() 返回的結果並不是全是被數組佔用了,還要包括一些 PHP 運行本身分配的一些結構,可能用內建函數產生的數組更接近真實的空間:

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

得到:
argv:54.5792byte
argv:54.5792byte

從這個結果來看似乎一個數組元素大約佔用了54個左右的位元組。再看看數組在Zend裡面的C結構,PHP中的陣列變數,首先需要一個 zval 結構:
struct _zval_struct {
   zvalue_value value;
   zend_uint refcount__gc;
   zend_uchar type;
   zend_uchar is_ref__gc;
};
zvalue_value 是一個union:
typedef union _zvalue_value {
   long lval;
   double dval;
   struct {
       char *val;
       int len;
   } str;
   HashTable *ht;
   zend_object_value obj;
} zvalue_value;

通常 zval 結構需要 8+6=14 個位元組,PHP中每個變數都有對應的 zval,但是數組,字串和對象還需要另外的儲存結構,而數組則是一個 HashTable :
typedef struct _hashtable {
    uint nTableSize;
    uint nTableMask;
    uint nNumOfElements;
    ulong nNextFreeElement;
    Bucket *pInternalPointer;
    Bucket *pListHead;
    Bucket *pListTail;
    Bucket **arBuckets;
    dtor_func_t pDestructor;
    zend_bool persistent;
    unsigned char nApplyCount;
    zend_bool bApplyProtection;
} HashTable;
HashTable 結構需要 40 個位元組,每個數組元素儲存在 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];
} Bucket;
Bucket 結構需要 36 個位元組,鍵長超過四個位元組的部分附加在 Bucket 後面,而元素值很可能是一個 zval 結構,另外每個數組會分配一個由 arBuckets 指向的 Bucket 指標數組, 雖然不能說每增加一個元素就需要一個指標,但是實際情況可能更糟。這麼算來一個數組元素就會佔用 54 個位元組,與上面的估算幾乎一樣。
    一個空數組至少會佔用 14(zval) + 40(HashTable) + 32(arBuckets) = 86 個位元組,作為一個變數應該在符號表中有個位置,也是一個數組元素,因此一個空陣列變數需要 118 個位元組來描述和儲存。從空間的角度來看,小型數組平均代價較大,當然一個指令碼中不會充斥數量很大的小型數組,可以以較小的空間代價來擷取編程上的快捷。但如果將數組當作容器來使用就是另一番景象了,實際應用經常會遇到多維陣列,而且元素居多。比如10k個元素的一維數組大概消耗540k記憶體,而10k x 10 的二維數組理論上只需要 6M 左右的空間,但是按照 memory_get_usage 的結果則兩倍於此,[10k,5,2]的三維數組居然消耗了23M,小型數組果然是划不來的。

http://blog.csdn.net/hguisu/article/details/7376705

我們在前面的php高效寫法提到,盡量不要複製變數,特別是數組。一般來說,PHP數組的記憶體利用率只有 1/10, 也就是說,一個在C語言裡面100M 記憶體的數組,在PHP裡面就要1G。下面我們可以粗略的估算PHP數組佔用記憶體的大小,首先我們測試1000個元素的整數佔用的記憶體:

<?php      echo memory_get_usage() , '<br>';      $start = memory_get_usage();      $a = Array();      for ($i=0; $i<1000; $i++) {      $a[$i] = $i + $i;      }      $mid =  memory_get_usage();      echo memory_get_usage() , '<br>';      for ($i=1000; $i<2000; $i++) {      $a[$i] = $i + $i;      }      $end =  memory_get_usage();      echo memory_get_usage() , '<br>';      echo 'argv:', ($mid - $start)/1024 ,'kb' , '<br>';      echo 'argv:',($end - $mid)/1024 ,'kb' , '<br>';  

輸出是:

350752
435248
519424
argv:84.416byte
argv:84.176byte

大概瞭解1000 個元素的整數數組需要佔用 82k 記憶體,平均每個元素佔用 84 個位元組。而純 C 中整體只需要 4k(一個整型佔用4byte * 1000 )。memory_get_usage() 返回的結果並不是全是被數組佔用了,還要包括一些 PHP 運行本身分配的一些結構,可能用內建函數產生的數組更接近真實的空間:

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

得到:
argv:54.5792byte
argv:54.5792byte

從這個結果來看似乎一個數組元素大約佔用了54個左右的位元組。再看看數組在Zend裡面的C結構,PHP中的陣列變數,首先需要一個 zval 結構:
struct _zval_struct {
   zvalue_value value;
   zend_uint refcount__gc;
   zend_uchar type;
   zend_uchar is_ref__gc;
};
zvalue_value 是一個union:
typedef union _zvalue_value {
   long lval;
   double dval;
   struct {
       char *val;
       int len;
   } str;
   HashTable *ht;
   zend_object_value obj;
} zvalue_value;

通常 zval 結構需要 8+6=14 個位元組,PHP中每個變數都有對應的 zval,但是數組,字串和對象還需要另外的儲存結構,而數組則是一個 HashTable :
typedef struct _hashtable {
    uint nTableSize;
    uint nTableMask;
    uint nNumOfElements;
    ulong nNextFreeElement;
    Bucket *pInternalPointer;
    Bucket *pListHead;
    Bucket *pListTail;
    Bucket **arBuckets;
    dtor_func_t pDestructor;
    zend_bool persistent;
    unsigned char nApplyCount;
    zend_bool bApplyProtection;
} HashTable;
HashTable 結構需要 40 個位元組,每個數組元素儲存在 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];
} Bucket;
Bucket 結構需要 36 個位元組,鍵長超過四個位元組的部分附加在 Bucket 後面,而元素值很可能是一個 zval 結構,另外每個數組會分配一個由 arBuckets 指向的 Bucket 指標數組, 雖然不能說每增加一個元素就需要一個指標,但是實際情況可能更糟。這麼算來一個數組元素就會佔用 54 個位元組,與上面的估算幾乎一樣。
    一個空數組至少會佔用 14(zval) + 40(HashTable) + 32(arBuckets) = 86 個位元組,作為一個變數應該在符號表中有個位置,也是一個數組元素,因此一個空陣列變數需要 118 個位元組來描述和儲存。從空間的角度來看,小型數組平均代價較大,當然一個指令碼中不會充斥數量很大的小型數組,可以以較小的空間代價來擷取編程上的快捷。但如果將數組當作容器來使用就是另一番景象了,實際應用經常會遇到多維陣列,而且元素居多。比如10k個元素的一維數組大概消耗540k記憶體,而10k x 10 的二維數組理論上只需要 6M 左右的空間,但是按照 memory_get_usage 的結果則兩倍於此,[10k,5,2]的三維數組居然消耗了23M,小型數組果然是划不來的。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

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.