一个PHP数组应该有多大的分析


Posted in PHP onJuly 30, 2009

虽然通常在PHP中进行大量数组运算从一定程度上反应程序设计上可能存在问题,但是粗略的估计数组占用的内存是很有必要的。
首先感觉一下1000个元素的整数数组占有的内存:

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 个元素的整数数组需要占用 100k 内存,平均每个元素占用 100 个字节。而纯 C 中整体只需要 4k。memory_get_usage() 返回的结果并不是全是被数组占用了,还要包括一些 PHP 运行本身分配的一些结构,可能用内置函数生成的数组更接近真实的空间:
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
从这个结果来看似乎一个数组元素大约只占用了 60 个左右的字节。再看看数组的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,小型数组果然是划不来的。
PHP 相关文章推荐
PHP 定界符 使用技巧
Jun 14 PHP
php 搜索框提示(自动完成)实例代码
Feb 05 PHP
鸡肋的PHP单例模式应用详解
Jun 03 PHP
慎用preg_replace危险的/e修饰符(一句话后门常用)
Jun 19 PHP
thinkphp区间查询、统计查询与SQL直接查询实例分析
Nov 24 PHP
thinkphp的URL路由规则与配置实例
Nov 26 PHP
PHP session文件独占锁引起阻塞问题解决方法
May 12 PHP
PHP实现GIF图片验证码
Nov 04 PHP
PHP更安全的密码加密机制Bcrypt详解
Jun 18 PHP
PHP Class SoapClient not found解决方法
Jan 20 PHP
win10 apache配置虚拟主机后localhost无法使用的解决方法
Jan 27 PHP
laravel Model 执行事务的实现
Oct 10 PHP
PHP UTF8编码内的繁简转换类
Jul 20 #PHP
php 验证码制作(网树注释思想)
Jul 20 #PHP
php PDO中文乱码解决办法
Jul 20 #PHP
PHP 配置文件中open_basedir选项作用
Jul 19 #PHP
PHP form 表单传参明细研究
Jul 17 #PHP
php与php MySQL 之间的关系
Jul 17 #PHP
php 图片上传类代码
Jul 17 #PHP
You might like
解析百度搜索结果link?url=参数分析 (全)
2012/10/09 PHP
php银联网页支付实现方法
2015/03/04 PHP
老生常谈PHP面向对象之解释器模式
2017/05/17 PHP
Aptana调试javascript图解教程
2009/11/30 Javascript
JavaScript设计模式之工厂模式和构造器模式
2015/02/11 Javascript
jQuery实现的输入框选择时间插件用法实例
2015/02/28 Javascript
JavaScript内存管理介绍
2015/03/13 Javascript
JavaScript 面向对象与原型
2015/04/10 Javascript
JavaScript中有关一个数组中最大值和最小值及它们的下表的输出的解决办法
2016/07/01 Javascript
Nodejs下DNS缓存问题浅析
2016/11/16 NodeJs
Bootstrap表单控件使用方法详解
2017/01/11 Javascript
微信小程序之数据绑定原理解析
2019/08/14 Javascript
vue 微信分享回调iOS和安卓回调出现错误的解决
2020/09/07 Javascript
[03:03]2014DOTA2国际邀请赛 EG战队专访
2014/07/12 DOTA
[02:41]2015国际邀请赛中国区预选赛观战指南
2015/05/20 DOTA
Python ORM框架SQLAlchemy学习笔记之安装和简单查询实例
2014/06/10 Python
python 接口_从协议到抽象基类详解
2017/08/24 Python
基于python3 类的属性、方法、封装、继承实例讲解
2017/09/19 Python
Python中getpass模块无回显输入源码解析
2018/01/11 Python
python实现linux下抓包并存库功能
2018/07/18 Python
python实现图片中文字分割效果
2019/07/22 Python
pytorch 常用线性函数详解
2020/01/15 Python
TensorFlow通过文件名/文件夹名获取标签,并加入队列的实现
2020/02/17 Python
Django model.py表单设置默认值允许为空的操作
2020/05/19 Python
CSS3实现多样的边框效果
2018/05/04 HTML / CSS
详解canvas绘制多张图的排列顺序问题
2019/01/21 HTML / CSS
英国家喻户晓的高街品牌:River Island
2017/11/28 全球购物
廉价连衣裙和婚纱礼服在线销售:Tbdress
2019/02/28 全球购物
园长自我鉴定
2013/10/06 职场文书
医院总经理职责
2013/12/26 职场文书
优质服务演讲稿
2014/05/14 职场文书
求职简历自荐信
2014/06/18 职场文书
2014年精神文明建设工作总结
2014/11/19 职场文书
担保书怎么写 ?
2019/04/22 职场文书
2019感恩宣传标语!
2019/07/05 职场文书
社交电商模式的兴起:这些新的商机千万别错过
2019/07/26 职场文书