一个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数组函数序列之array_slice() - 在数组中根据条件取出一段值,并返回
Nov 07 PHP
php使用异或实现的加密解密实例
Sep 04 PHP
php 修改、增加xml结点属性的实现代码
Oct 22 PHP
关于URL最大长度限制的相关资料查证
Dec 23 PHP
PHP中iconv函数转码时截断字符问题的解决方法
Jan 21 PHP
Symfony页面的基本创建实例详解
Jan 26 PHP
PHP版微信公众平台红包API
Apr 02 PHP
php提取身份证号码中的生日日期以及验证是否为成年人的函数
Sep 29 PHP
highchart数据源纵轴json内的值必须是int(详解)
Feb 20 PHP
PHP创建对象的六种方式实例总结
Jun 27 PHP
Laravel框架基础语法与知识点整理【模板变量、输出、include引入子视图等】
Dec 03 PHP
php获取是星期几的的一些常用姿势
Dec 15 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内存相关的功能特性详解
2013/06/08 PHP
Yii结合CKEditor实现图片上传功能
2014/06/13 PHP
php实现模拟登陆方正教务系统抓取课表
2015/05/19 PHP
thinkPHP5.0框架开发规范简介
2017/03/25 PHP
自定义Laravel (monolog)日志位置,并增加请求ID的实现
2019/10/17 PHP
JavaScript 常见对象类创建代码与优缺点分析
2009/12/07 Javascript
js 页面关闭前的出现提示的实现代码
2011/05/25 Javascript
node.js中的fs.realpath方法使用说明
2014/12/16 Javascript
jQuery中prop()方法用法实例
2015/01/05 Javascript
jQuery中ready事件用法实例
2015/01/19 Javascript
JS中位置与大小的获取方法
2016/11/22 Javascript
JavaScript利用正则表达式替换字符串中的内容
2016/12/12 Javascript
基于Angular.js实现的触摸滑动动画实例代码
2017/02/19 Javascript
浅谈angularjs依赖服务注入写法的注意点
2017/04/24 Javascript
d3.js入门教程之数据绑定详解
2017/04/28 Javascript
Vue动态实现评分效果
2017/05/24 Javascript
React学习笔记之事件处理(二)
2017/07/02 Javascript
AngularJS常见过滤器用法实例总结
2017/07/06 Javascript
将jquery.qqFace.js表情转换成微信的字符码
2017/12/01 jQuery
微信小程序wxml列表渲染原理解析
2019/11/27 Javascript
[48:28]完美世界DOTA2联赛循环赛FTD vs Magma第二场 10月30日
2020/10/31 DOTA
Python pickle类库介绍(对象序列化和反序列化)
2014/11/21 Python
Python数据结构与算法之字典树实现方法示例
2017/12/13 Python
详谈Pandas中iloc和loc以及ix的区别
2018/06/08 Python
Python3实现爬虫爬取赶集网列表功能【基于request和BeautifulSoup模块】
2018/12/05 Python
使用Python实现分别输出每个数组
2019/12/06 Python
Windows下pycharm安装第三方库失败(通用解决方案)
2020/09/17 Python
Python 找出英文单词列表(list)中最长单词链
2020/12/14 Python
学生周末回家住宿长期请假条
2014/02/15 职场文书
房产委托公证书
2014/04/08 职场文书
护理学专业求职信
2014/06/29 职场文书
欢送会主持词
2015/07/01 职场文书
2015年小学实验室工作总结
2015/07/28 职场文书
小学体育教学随笔
2015/08/14 职场文书
2016年安康杯竞赛活动总结
2016/04/05 职场文书
python高温预警数据获取实例
2022/07/23 Python