亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > PHP > 正文

PHP數組和值到底有多大

2020-03-22 19:42:42
字體:
來源:轉載
供稿:網友
這篇文章是關于PHP 5的內存使用情況。對于本文所述的情況,PHP 7中的內存使用量大約低3倍。

在這篇文章中,我想以下面的腳本為例來研究PHP數組(以及一般的值)的內存使用情況,該腳本創建了100000個惟一的整數數組元素,并測量了結果的內存使用情況:

$startMemory = memory_get_usage();$array = range(1, 100000);echo memory_get_usage() - $startMemory, bytes 

你希望它是多少?簡單來說,一個整數是8字節(在64位unix機器上使用long類型),您得到100,000個整數,因此顯然需要800000字節。

現在嘗試運行上面的代碼。這就得到了14649024字節。是的,你沒聽錯,是13.97 MB,比我們估計的多18倍。

那么,18的額外因數是怎么來的呢?

總結

對于那些不想知道整個故事的人,這里有一個涉及到的不同組件的內存使用的快速總結:

 | 64 bit | 32 bit---------------------------------------------------zval | 24 bytes | 16 bytes+ cyclic GC info | 8 bytes | 4 bytes+ allocation header | 16 bytes | 8 bytes===================================================zval (html' target='_blank'>value) total | 48 bytes | 28 bytes===================================================bucket | 72 bytes | 36 bytes+ allocation header | 16 bytes | 8 bytes+ pointer | 8 bytes | 4 bytes===================================================bucket (array element) total | 96 bytes | 48 bytes===================================================total total | 144 bytes | 76 bytes

上述數字將根據您的操作系統、編譯器和編譯選項的不同而有所不同。例如,如果您使用調試或線程安全來編譯PHP,您將得到不同的數字。但是我認為上面給出的大小是您將在Linux上的PHP 5.3的64位生產版本中看到的大小。

如果你用這144字節乘以100000個元素,你會得到14400000字節,也就是13.73 MB,這與實際數字非常接近——剩下的大部分都是未初始化bucket的指針,但是我將在后面討論這個問題。

現在,如果您想對上面提到的值進行更詳細的分析,請繼續閱讀:)

zvalue_value聯盟

首先看看PHP是如何存儲值的。正如您所知道的,PHP是一種弱類型語言,因此它需要某種方式在各種類型之間快速切換。PHP為此使用union,它在zend中定義如下。

typedef union _zvalue_value { long lval; // For integers and booleans double dval; // For floats (doubles) struct { // For strings char *val; // consisting of the string itself int len; // and its length } str; HashTable *ht; // For arrays (hash tables) zend_object_value obj; // For objects} zvalue_value;

如果您不知道C,這不是一個問題,因為代碼非常簡單:union是一種使某些值可以作為各種類型訪問的方法。例如,如果您執行zvalue_value- lval,您將得到一個被解釋為整數的值。另一方面,如果您使用zvalue_value- ht,則該值將被解釋為指向哈希表(即數組)的指針。

但我們不要在這里講太多。對我們來說,唯一重要的是一個union的大小等于它的最大組件的大小。這里最大的組件是字符串結構體(zend_object_value結構體的大小與str結構體相同,但為了簡單起見,我將省略它)。string struct存儲一個指針(8字節)和一個整數(4字節),總共是12字節。由于內存對齊(12字節的結構并不酷,因為它們不是64位/ 8字節的倍數),結構的總大小將是16字節,這也是union作為一個整體的大小。

現在我們知道,由于PHP的動態類型,每個值不需要8字節,而是16字節。乘以100000個值得到1600000字節,也就是1.53 MB,但是實際的值是13.97 MB,所以我們還不能得到它。

zval的結構

這非常符合邏輯——union只存儲值本身,但是PHP顯然還需要存儲類型和一些垃圾收集信息。保存此信息的結構稱為zval,您可能已經聽說過它。關于PHP為什么需要它的更多信息,我建議閱讀Sara Golemon的一篇文章。無論如何,這個結構的定義如下:

struct _zval_struct { zvalue_value value; // The value zend_uint refcount__gc; // The number of references to this value (for GC) zend_uchar type; // The type zend_uchar is_ref__gc; // Whether this value is a reference ( )};

結構的大小由其組件的大小之和決定:zvalue_value為16字節(如上所計算),zend_uint為4字節,zend_uchars為1字節??偣彩?2字節。由于內存對齊,實際大小將是24字節。

因此,如果我們存儲100,000個元素a 24字節,那么總共就是2400000,也就是2.29 MB,差距正在縮小,但是實際值仍然是原來的6倍多。

循環收集器(從PHP 5.3開始)

PHP 5.3引入了一個新的循環引用垃圾收集器。為此,PHP必須存儲一些額外的數據。我不想在這里解釋這個算法是如何工作的,你可以在手冊的鏈接頁上讀到。對于我們的大小計算來說,重要的是PHP將把每個zval包裝成zval_gc_info:

typedef struct _zval_gc_info { zval z; union { gc_root_buffer *buffered; struct _zval_gc_info *next; } u;} zval_gc_info;

正如您所看到的,Zend只在它上面添加了一個union,它由兩個指針組成。希望您還記得,union的大小就是它最大的組件的大小:兩個union組件都是指針,因此它們的大小都是8字節。所以union的大小也是8字節。

如果我們把它加到24字節上面我們已經有32字節了。再乘以100000個元素,我們得到的內存使用量是3。05 MB。

Zend MM分配器

C與PHP不同,它不為您管理內存。你需要自己記錄你的分配。為此,PHP使用了專門針對其需要優化的自定義內存管理器:Zend內存管理器。Zend MM基于Doug Lea的malloc,并添加了一些PHP特有的優化和特性(如內存限制、每次請求后清理等)。

這里對我們來說重要的是,MM為通過它完成的每個分配添加一個分配頭。定義如下:

typedef struct _zend_mm_block { zend_mm_block_info info;#if ZEND_DEBUG unsigned int magic;# ifdef ZTS THREAD_T thread_id;# endif zend_mm_debug_info debug;#elif ZEND_MM_HEAP_PROTECTION zend_mm_debug_info debug;#endif} zend_mm_block;typedef struct _zend_mm_block_info {#if ZEND_MM_COOKIES size_t _cookie;#endif size_t _size; // size of the allocation size_t _prev; // previous block (not sure what exactly this is)} zend_mm_block_info;

如您所見,這些定義充斥著大量的編譯選項檢查。如果你用堆保護,多線程,調試和MM cookie來構建PHP,那么如果你用堆保護,多線程,調試和MM cookie來構建PHP,那么如果你用堆保護,多線程,調試和MM cookie來構建PHP,那么分配頭文件會更大。

對于本例,我們假設所有這些選項都是禁用的。在這種情況下,只剩下兩個size_ts _size和_prev。size_t有8個字節(在64位上),所以分配頭的總大小是16個字節——并且在每個分配上都添加了這個頭。

現在我們需要再次調整zval大小。實際上,它不是32字節,而是48字節,這是由分配頭決定的。乘以100000個元素是4。58 MB,實際值是13。97 MB,所以我們已經得到了大約三分之一的面積。

Buckets

到目前為止,我們只考慮單個值。但是PHP中的數組結構也會占用大量空間:“數組”在這里實際上是一個不合適的術語。PHP數組實際上是散列表/字典。那么哈希表是如何工作的呢?基本上,對于每個鍵,都會生成一個散列,該散列用作“real”C數組的偏移量。由于哈希值可能會沖突,具有相同哈希值的所有元素都存儲在鏈表中。當訪問一個元素時,PHP首先計算散列,查找正確的bucket并遍歷鏈接列表,逐個元素比較確切的鍵。bucket的定義如下:

typedef struct bucket { ulong h; // The hash (or for int keys the key) uint nKeyLength; // The length of the key (for string keys) void *pData; // The actual data void *pDataPtr; // ??? What s this ??? struct bucket *pListNext; // PHP arrays are ordered. This gives the next element in that order struct bucket *pListLast; // and this gives the previous element struct bucket *pNext; // The next element in this (doubly) linked list struct bucket *pLast; // The previous element in this (doubly) linked list const char *arKey; // The key (for string keys)} Bucket;

正如您所看到的,需要存儲大量數據才能獲得PHP使用的抽象數組數據結構(PHP數組同時是數組、字典和鏈表,這當然需要大量信息)。單個組件的大小為無符號long為8字節,無符號int為4字節,指針為7乘以8字節??偣彩?8。添加對齊,得到72字節。

像zvals這樣的bucket需要在頭部分配,因此我們需要再次為分配頭添加16個字節,從而得到88個字節。我們還需要在“real”C數組中存儲指向這些Bucket的指針(Bucket ** arbucket;)我上面提到過,每個元素增加8個字節。所以總的來說,每個bucket需要96字節的存儲空間。

如果每個值都需要一個bucket,那么bucket是96字節,zval是48字節,總共144字節。對于100000個元素,也就是14400000字節,即13.73 MB。

神秘的解決。

等等,還有0.24 MB !

最后的0.24 MB是由于未初始化的存儲bucket造成的:理想情況下,存儲bucket的實際C數組的大小應該與存儲的數組元素的數量大致相同。通過這種方式,沖突最少(除非希望浪費大量內存)。但是PHP顯然不能在每次添加元素時重新分配整個數組——這將非常緩慢。相反,如果內部bucket數組達到限制,PHP總是將其大小加倍。所以數組的大小總是2的冪。

在我們的例子中是2 ^ 17 = 131072。但是我們只需要100000個bucket,所以我們留下31072個bucket沒有使用。這些bucket不會被分配(因此我們不需要花費全部的96字節),但是bucket指針(存儲在內部桶數組中的那個)的內存仍然需要分配。所以我們另外使用8字節(一個指針)* 31072個元素。這是248576字節或0.23 MB,與丟失的內存匹配。(當然,這里仍然缺少一些字節,但是我不想在這里介紹。比如哈希表結構本身,變量等等)

神秘真的解決了。

這告訴我們什么?

PHP不是c,這就是所有這些告訴我們的。您不能期望像PHP這樣的超級動態語言具有與C語言相同的高效內存使用。你不能。

但是,如果您確實想節省內存,可以考慮使用SplFixedArray處理大型靜態數組。

看看這個修改后的腳本:

$startMemory = memory_get_usage();$array = new SplFixedArray(100000);for ($i = 0; $i 100000; ++$i) { $array[$i] = $i;echo memory_get_usage() - $startMemory, bytes 

它基本上做的是相同的事情,但是如果運行它,您會注意到它只使用了“5600640字節”。這是每個元素56字節,因此比普通數組使用的每個元素144字節要少得多。這是因為一個固定的數組不需要bucket結構:所以它只需要每個元素一個zval(48字節)和一個指針(8字節),從而得到觀察到的56字節。

以上就是PHP數組和值到底有多大的詳細內容,PHP教程

鄭重聲明:本文版權歸原作者所有,轉載文章僅為傳播更多信息之目的,如作者信息標記有誤,請第一時間聯系我們修改或刪除,多謝。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产在线日韩在线| 日韩电影在线观看免费| 欧美极品美女电影一区| 久久久国产一区| 欧洲精品久久久| 欧美老女人www| 亚洲黄色在线观看| 91在线免费观看网站| 国产精品一久久香蕉国产线看观看| 91精品国产自产在线观看永久| 日韩免费观看在线观看| 正在播放国产一区| 日韩欧美在线播放| 亚洲电影免费观看高清完整版在线观看| 热99久久精品| 91网站在线看| 欧美性videos高清精品| 亚洲天堂网站在线观看视频| 亚洲国产毛片完整版| 菠萝蜜影院一区二区免费| 亚洲乱码一区二区| 国产精品h在线观看| 中文字幕精品一区久久久久| 欧美一二三视频| 性色av香蕉一区二区| 欧美国产第二页| 亚洲欧美日韩国产精品| 性色av香蕉一区二区| 国产精品福利片| 亚洲第一区第二区| 国产日韩av在线播放| 亚洲xxxx在线| 欧美三级欧美成人高清www| 亚洲欧美中文日韩在线| 欧美中文在线观看| 亚洲国产精品女人久久久| 亚洲色图激情小说| 2021久久精品国产99国产精品| 亚洲欧美日韩在线高清直播| 国产成人在线视频| 一个人看的www欧美| 国产香蕉97碰碰久久人人| 欧美老少做受xxxx高潮| 国产+成+人+亚洲欧洲| 亚洲欧美在线第一页| 欧美激情乱人伦一区| 日韩精品有码在线观看| 黄色成人在线免费| 51久久精品夜色国产麻豆| 日本在线精品视频| 成人午夜激情免费视频| 成人福利网站在线观看| 色婷婷av一区二区三区在线观看| 亚洲欧洲日产国码av系列天堂| 亚洲色图18p| 亚洲自拍欧美另类| 欧美另类极品videosbest最新版本| 午夜精品国产精品大乳美女| 国产精品小说在线| 成人国产在线视频| 日韩在线免费av| 国产精品视频网站| 欧美亚洲第一区| 亚洲欧美国产日韩天堂区| 国产精品中文在线| 日韩在线观看成人| 日韩中文字幕精品| 欧美激情在线观看| 国产在线视频91| 成人动漫网站在线观看| 久久香蕉精品香蕉| 亚洲sss综合天堂久久| 亚洲高清免费观看高清完整版| 亚洲国产成人精品久久久国产成人一区| 色av中文字幕一区| 精品久久中文字幕久久av| 国产亚洲精品激情久久| 欧美刺激性大交免费视频| 午夜精品理论片| 日韩精品视频观看| 成人国产精品免费视频| 亚洲国产高清高潮精品美女| 日韩亚洲欧美中文在线| 国产午夜精品免费一区二区三区| 亚洲图片欧美午夜| 久久久精品国产一区二区| 久久久久久久香蕉网| 日韩毛片在线看| 日本久久久久久久| 国产成人精品国内自产拍免费看| 精品色蜜蜜精品视频在线观看| 亚洲性日韩精品一区二区| 欧美日韩美女在线| 不卡在线观看电视剧完整版| 亚洲福利视频专区| 亚洲黄在线观看| 亚洲第一精品久久忘忧草社区| 一本色道久久综合狠狠躁篇怎么玩| 欧美疯狂性受xxxxx另类| 日韩中文在线观看| 国产日韩av高清| 欧美成人免费全部观看天天性色| 欧美猛少妇色xxxxx| 国产精品6699| 亚洲欧美另类自拍| 欧美裸体xxxx极品少妇| 日本精品一区二区三区在线| 欧美大片在线影院| 一区二区三区 在线观看视| y97精品国产97久久久久久| 久久91亚洲精品中文字幕奶水| 91国自产精品中文字幕亚洲| 伊人伊成久久人综合网站| 26uuu久久噜噜噜噜| 一区二区三区回区在观看免费视频| 亚洲欧美日韩精品久久奇米色影视| 粗暴蹂躏中文一区二区三区| 日本中文字幕不卡免费| 伦伦影院午夜日韩欧美限制| 国产精品久久久久久久久久久不卡| 国产在线精品成人一区二区三区| 日韩一区二区精品视频| 亚洲成av人片在线观看香蕉| 亚洲精品永久免费| 日韩成人av网址| 久久精品亚洲一区| 国产91精品不卡视频| 亚洲春色另类小说| 国产成人福利夜色影视| 国产最新精品视频| 亚洲色图狂野欧美| 国产精品视频最多的网站| 亚洲欧美中文日韩在线v日本| 久久久久久久久久久av| 日本中文字幕久久看| www.xxxx精品| 九九精品视频在线观看| 日韩欧美精品在线观看| 欧美精品日韩www.p站| 国产精品欧美亚洲777777| 大荫蒂欧美视频另类xxxx| 亚洲国产一区自拍| 久久久久国色av免费观看性色| 亚洲成人黄色网址| 欧美激情精品久久久久久免费印度| 国产精品欧美一区二区三区奶水| 亚洲人线精品午夜| 国产精品日韩欧美| 青青在线视频一区二区三区| 成人在线一区二区| 97国产suv精品一区二区62| 久久6精品影院| 69av视频在线播放| 永久555www成人免费| 美女久久久久久久| 国产精品福利网站| 91在线免费观看网站| 久久久噜噜噜久久中文字免| 欧美极品少妇xxxxⅹ喷水| 欧美激情一级二级| 亚洲人成电影在线观看天堂色| 国产欧美一区二区| 日韩有码在线播放| 神马久久桃色视频|