国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 語言 > PHP > 正文

PHP數組內存利用率低和弱類型詳細解讀

2024-05-04 23:59:20
字體:
來源:轉載
供稿:網友

這兩天任務提前完成,可以喘口氣沉淀一下,深入學習學習PHP。其實本來是想了解一下PHP性能優(yōu)化相關的東西,但被網上的一句“PHP數組內存利用率低,C語言100MB的內存數組,PHP里需要1G”驚到了。PHP真的這么耗內存么?于是借此機會了解了PHP的數據類型實現方式。

先來做個測試:

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

所得結果:

    353352
    437848
    argv:84.416bytes

1000個元素的整數數組耗費內存(437848 - 353352)字節(jié),約合82KB,也就是說每個元素所占內存84字節(jié)。在C語言中,一個int占位是4字節(jié),整體相差了20倍。

但是網上又說memery_get_usage()返回的結果不全是數組占用,還包括PHP本身的一些結構,因此,換種方式,采用PHP內置函數生成數組試試:

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

 輸出為:

argv:54.5792byte

比剛才略好,但也54字節(jié),確實差了10倍左右。

究其原因,還得從PHP的底層實現說起。PHP是一種弱類型的語言,不分int,double,string之類的,統(tǒng)一一個'$'就能解決所有問題。PHP底層由C語言實現,每個變量都對應一個zval結構,其詳細定義為:

typedef struct _zval_struct zval; struct _zval_struct {   /* Variable information */   zvalue_value value;   /* The value 1 12字節(jié)(32位機是12,64位機需要8+4+4=16) */   zend_uint refcount__gc; /* The number of references to this value (for GC) 4字節(jié) */   zend_uchar type;    /* The active type 1字節(jié)*/   zend_uchar is_ref__gc; /* Whether this value is a reference (&) 1字節(jié)*/ }; 

PHP使用union結構來存儲變量的值,zval中zvalue_value類型的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; 

union類型占用內存的大小有其最大的成員所占的數據空間決定。在zvalue_value中,str結構體的int占4字節(jié),char指針占4字節(jié),故整個zvalue_value所占內存為8字節(jié)。

zval的大小即為8 + 4 + 1 + 1 = 14字節(jié)。

注意到zvalue_value中還有一個HashTable是做什么的?zval中,數組、字符串和對象還需要另外的存儲結構,數組的存儲結構即為HashTable。

HashTable定義給出:

typedef struct _hashtable {    uint nTableSize; //表長度,并非元素個數    uint nTableMask;//表的掩碼,始終等于nTableSize-1    uint nNumOfElements;//存儲的元素個數    ulong nNextFreeElement;//指向下一個空的元素位置    Bucket *pInternalPointer;//foreach循環(huán)時,用來記錄當前遍歷到的元素位置    Bucket *pListHead;    Bucket *pListTail;    Bucket **arBuckets;//存儲的元素數組    dtor_func_t pDestructor;//析構函數    zend_bool persistent;//是否持久保存。從這可以發(fā)現,PHP數組是可以實現持久保存在內存中的,而無需每次請求都重新加載。    unsigned char nApplyCount;    zend_bool bApplyProtection; } HashTable; 

除了幾個記錄table大小,所含元素數量的屬性變量外,Bucket被多次使用到,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就像是一個鏈表節(jié)點,有具體的數據和指針,而HashTable就是一個array,保存著一串Bucket元素。PHP中多維數組的實現,不過就是Bucket里面存著另一個HashTable罷了。

算一算HashTable需要占用39個字節(jié),Bucket需要33個字節(jié)。一個空的數組就需要占用14 + 39 + 33 = 86個字節(jié)。Bucket 結構需要 33 個字節(jié),鍵長超過四個字節(jié)的部分附加在 Bucket 后面,而元素值很可能是一個 zval 結構,另外每個數組會分配一個由 arBuckets 指向的 Bucket 指針數組, 雖然不能說每增加一個元素就需要一個指針,但是實際情況可能更糟。這么算來一個數組元素就會占用 54 個字節(jié),與上面的估算幾乎一樣。

從空間的角度來看,小型數組平均代價較大,當然一個腳本中不會充斥數量很大的小型數組,可以以較小的空間代價來獲取編程上的快捷。但如果將數組當作容器來使用就是另一番景象了,實際應用經常會遇到多維數組,而且元素居多。比如10k個元素的一維數組大概消耗540k內存,而10k x 10 的二維數組理論上只需要 6M 左右的空間,但是按照 memory_get_usage 的結果則兩倍于此,[10k,5,2]的三維數組居然消耗了23M,小型數組確實是劃不來的。

PHP數組內存利用率低的原因,講到這里,接下來的文章將解讀PHP數組操作的具體實現。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VeVb武林網。


注:相關教程知識閱讀請移步到PHP教程頻道。
發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表

圖片精選

主站蜘蛛池模板: 永嘉县| 小金县| 阿拉善左旗| 金乡县| 环江| 隆安县| 武定县| 定边县| 涪陵区| 隆子县| 阳西县| 根河市| 封丘县| 旅游| 乳源| 涡阳县| 大埔县| 交城县| 连江县| 许昌县| 治县。| 周至县| 桑植县| 鹿邑县| 宝丰县| 繁昌县| 兰溪市| 吉林市| 都安| 高青县| 天全县| 平邑县| 桑日县| 长治市| 望城县| 三门峡市| 宜都市| 汉川市| 大连市| 邢台市| 库尔勒市|