一个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 5.0对象模型深度探索之对象复制
Mar 27 PHP
PHP管理内存函数 memory_get_usage()使用介绍
Sep 23 PHP
PHP登陆后跳转到登陆前页面实现思路及代码
Jan 17 PHP
PHP根据两点间的经纬度计算距离
Oct 31 PHP
使用PHP把HTML生成PDF文件的几个开源项目介绍
Nov 17 PHP
php+mysql数据库查询实例
Jan 21 PHP
yii2超好用的日期组件和时间组件
May 05 PHP
php 从指定数字中获取随机组合的简单方法(推荐)
Apr 05 PHP
PHP实现链式操作的三种方法详解
Nov 16 PHP
PHP实现的多维数组去重操作示例
Jul 21 PHP
深入理解 PHP7 中全新的 zval 容器和引用计数机制
Oct 15 PHP
php的命名空间与自动加载实现方法
Aug 25 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
PHP中的类-什么叫类
2006/11/20 PHP
用PHP制作的意见反馈表源码
2007/03/11 PHP
PHPWind 发帖回帖Api PHP版打包下载
2010/02/08 PHP
php中常用的预定义变量小结
2012/05/09 PHP
php实现概率性随机抽奖代码
2016/01/02 PHP
encode脚本和normal脚本混用的问题与解决方法
2007/03/08 Javascript
jQuery+CSS 实现随滚动条增减的汽水瓶中的液体效果
2011/09/26 Javascript
DIV+CSS+JS不间断横向滚动实现代码
2013/03/19 Javascript
一款基于jQuery的图片场景标注提示弹窗特效
2015/01/05 Javascript
基于MVC4+EasyUI的Web开发框架形成之旅之界面控件的使用
2015/12/16 Javascript
学习JavaScript设计模式之模板方法模式
2016/01/20 Javascript
js select实现省市区联动选择
2020/04/17 Javascript
基于React实现表单数据的添加和删除详解
2017/03/14 Javascript
Angular 向组件传递模板的两种方法
2018/02/23 Javascript
详解vue中点击空白处隐藏div的实现(用指令实现)
2018/04/19 Javascript
vue style width a href动态拼接问题的解决
2020/08/07 Javascript
Vue+Element自定义纵向表格表头教程
2020/10/26 Javascript
Python实现利用最大公约数求三个正整数的最小公倍数示例
2017/09/30 Python
python3安装speech语音模块的方法
2018/12/24 Python
对python:threading.Thread类的使用方法详解
2019/01/31 Python
Python 限制线程的最大数量的方法(Semaphore)
2019/02/22 Python
linux环境下Django的安装配置详解
2019/07/22 Python
python cv2在验证码识别中应用实例解析
2019/12/25 Python
python实现在一个画布上画多个子图
2020/01/19 Python
Python实现遗传算法(二进制编码)求函数最优值方式
2020/02/11 Python
python 实现弹球游戏的示例代码
2020/11/17 Python
CSS3制作酷炫的三维相册效果
2016/07/01 HTML / CSS
localStorage 设置过期时间的方法实现
2018/12/21 HTML / CSS
物业管理员岗位职责范文
2013/11/25 职场文书
财务会计专业推荐信
2013/11/30 职场文书
导游个人求职信
2014/04/25 职场文书
降价通知函
2015/04/23 职场文书
2015年医务科工作总结范文
2015/05/26 职场文书
2015年助理政工师工作总结
2015/05/26 职场文书
SQL实现LeetCode(177.第N高薪水)
2021/08/04 MySQL
浅析CSS在DevTools 中架构演变
2021/10/05 HTML / CSS