一個(gè)PHP數(shù)組應(yīng)該有多大的分析
雖然通常在PHP中進(jìn)行大量數(shù)組運(yùn)算從一定程度上反應(yīng)程序設(shè)計(jì)上可能存在問題,但是粗略的估計(jì)數(shù)組占用的內(nèi)存是很有必要的。
首先感覺一下1000個(gè)元素的整數(shù)數(shù)組占有的內(nèi)存:
echo memory_get_usage() . “\n”;
$a = Array();
for ($i=0; $i<1000; $i++) {
$a[$i] = $i + $i;
}
echo memory_get_usage() . “\n”;
for ($i=1000; $i<2000; $i++) {
$a[$i] = $i + $i;
}
echo memory_get_usage() . “\n”;
輸出是:
58176
162956
267088
大 約可以知道 1000 個(gè)元素的整數(shù)數(shù)組需要占用 100k 內(nèi)存,平均每個(gè)元素占用 100 個(gè)字節(jié)。而純 C 中整體只需要 4k。memory_get_usage() 返回的結(jié)果并不是全是被數(shù)組占用了,還要包括一些 PHP 運(yùn)行本身分配的一些結(jié)構(gòu),可能用內(nèi)置函數(shù)生成的數(shù)組更接近真實(shí)的空間:
echo “init mem: ” . memory_get_usage() . “\n”;
$a = array_fill(0, 10000, 1);
echo “10k elements: ” . memory_get_usage() . “, system: ” . memory_get_usage(true) . “\n”;
$b = array_fill(0, 10000, 1);
echo “10k elements: ” . memory_get_usage() . “, system: ” . memory_get_usage(true) . “\n”;
得到:
init mem: 58468
10k elements: 724696, system: 786432
10k elements: 1390464, system: 1572864
從這個(gè)結(jié)果來看似乎一個(gè)數(shù)組元素大約只占用了 60 個(gè)左右的字節(jié)。再看看數(shù)組的C結(jié)構(gòu),PHP 中的數(shù)組變量,首先需要一個(gè) zval 結(jié)構(gòu):
struct _zval_struct {
zvalue_value value;
zend_uint refcount__gc;
zend_uchar type;
zend_uchar is_ref__gc;
};
zvalue_value 是一個(gè)union:
typedef union _zvalue_value {
long lval;
double dval;
struct {
char *val;
int len;
} str;
HashTable *ht;
zend_object_value obj;
} zvalue_value;
通常 zval 結(jié)構(gòu)需要 8+6=14 個(gè)字節(jié),PHP中每個(gè)變量都有對(duì)應(yīng)的 zval,但是數(shù)組,字符串和對(duì)象還需要另外的存儲(chǔ)結(jié)構(gòu),而數(shù)組則是一個(gè) 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 結(jié)構(gòu)需要 40 個(gè)字節(jié),每個(gè)數(shù)組元素存儲(chǔ)在 Bucket 結(jié)構(gòu)中:
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 結(jié)構(gòu)需要 36 個(gè)字節(jié),鍵長(zhǎng)超過四個(gè)字節(jié)的部分附加在 Bucket 后面,而元素值很可能是一個(gè) zval 結(jié)構(gòu),另外每個(gè)數(shù)組會(huì)分配一個(gè)由 arBuckets 指向的 Bucket 指針數(shù)組, 雖然不能說每增加一個(gè)元素就需要一個(gè)指針,但是實(shí)際情況可能更糟。這么算來一個(gè)數(shù)組元素就會(huì)占用 54 個(gè)字節(jié),與上面的估算相差不遠(yuǎn)。
一個(gè)空數(shù)組至少會(huì)占用 14(zval) + 40(HashTable) + 32(arBuckets) = 86 個(gè)字節(jié),作為一個(gè)變量應(yīng)該在符號(hào)表中有個(gè)位置,也是一個(gè)數(shù)組元素,因此一個(gè)空數(shù)組變量需要 118 個(gè)字節(jié)來描述和存儲(chǔ)。從空間的角度來看,小型數(shù)組平均代價(jià)較大,當(dāng)然一個(gè)腳本中不會(huì)充斥數(shù)量很大的小型數(shù)組,可以以較小的空間代價(jià)來獲取編程上的快捷。
但如果將數(shù)組當(dāng)作容器來使用就是另一番景象了,實(shí)際應(yīng)用經(jīng)常會(huì)遇到多維數(shù)組,而且元素居多。比如10k個(gè)元素的一維數(shù)組大概消耗540k內(nèi)存,而10k x 10 的二維數(shù)組理論上只需要 6M 左右的空間,但是按照 memory_get_usage 的結(jié)果則兩倍于此,[10k,5,2]的三維數(shù)組居然消耗了23M,小型數(shù)組果然是劃不來的。
相關(guān)文章
PHP Zip壓縮 在線對(duì)文件進(jìn)行壓縮的函數(shù)
PHP在線對(duì)文件進(jìn)行Zip 壓縮函數(shù)代碼,用于使用PHP在線創(chuàng)建ZIP壓縮文件。2010-05-05Discuz!下Memcache緩存實(shí)現(xiàn)方法
在PHP+MySQL架構(gòu)的站點(diǎn)中,本文重點(diǎn)從MySQL的角度去分析如何使Discuz!論壇(或者類似的PHP+MySQL架構(gòu)的程序)應(yīng)對(duì)大訪問量。同時(shí)給出一些使用Memcache去減輕MySQL壓力的建議2010-05-05php計(jì)算給定時(shí)間之前的函數(shù)用法實(shí)例
這篇文章主要介紹了php計(jì)算給定時(shí)間之前的函數(shù)用法,實(shí)例分析了php計(jì)算時(shí)間的技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-04-04PHP中file_get_contents高級(jí)用法實(shí)例
這篇文章主要介紹了PHP中file_get_contents高級(jí)用法,包括了超時(shí)限制及實(shí)現(xiàn)POST等用法,需要的朋友可以參考下2014-09-09php強(qiáng)制用戶轉(zhuǎn)向www域名的方法
這篇文章主要介紹了php強(qiáng)制用戶轉(zhuǎn)向www域名的方法,可實(shí)現(xiàn)模擬301重定向的功能,并且針對(duì)無法head重定向的情況輸出鏈接,需要的朋友可以參考下2015-06-06基于php中echo用逗號(hào)和用點(diǎn)號(hào)的區(qū)別詳解
下面小編就為大家分享一篇基于php中echo用逗號(hào)和用點(diǎn)號(hào)的區(qū)別詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-01-01thinkphp多表查詢兩表有重復(fù)相同字段的完美解決方法
下面小編就為大家?guī)硪黄猼hinkphp多表查詢兩表有重復(fù)相同字段的完美解決方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-09-09