一个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 正则 过滤html 的超链接
Jun 02 PHP
解析php中的fopen()函数用打开文件模式说明
Jun 20 PHP
php颜色转换函数hex-rgb(将十六进制格式转成十进制格式)
Sep 23 PHP
php像数组一样存取和修改字符串字符
Mar 21 PHP
thinkphp的静态缓存用法分析
Nov 29 PHP
深入解析PHP中foreach语句控制数组循环的用法
Nov 30 PHP
PHP实现时间比较和时间差计算的方法示例
Jul 24 PHP
在Laravel5.6中使用Swoole的协程数据库查询
Jun 15 PHP
用php定义一个数组最简单的方法
Oct 04 PHP
laravel框架模型中非静态方法也能静态调用的原理分析
Nov 23 PHP
TP5框架实现上传多张图片的方法分析
Mar 29 PHP
如何在PHP中使用数组
Jun 09 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
自己动手,丰衣足食 - 短波框形天线制作
2021/03/01 无线电
PHP 下载文件时自动添加bom头的方法实例
2014/01/10 PHP
php ci框架中加载css和js文件失败的原因及解决方法
2014/07/29 PHP
自己写的php curl库实现整站克隆功能
2015/02/12 PHP
php中file_exists函数使用详解
2015/05/08 PHP
php简单获取复选框值的方法
2016/05/11 PHP
golang实现php里的serialize()和unserialize()序列和反序列方法详解
2018/10/30 PHP
清除网页历史记录,屏蔽后退按钮!
2008/12/22 Javascript
javascript 面向对象的JavaScript类
2010/05/04 Javascript
一个轻量级的javascript库 pj介绍
2010/12/19 Javascript
解释&amp;&amp;和||在javascript中的另类用法
2014/07/28 Javascript
jQuery关键词说明插件cluetip使用指南
2015/04/21 Javascript
javascript实现设置、获取和删除Cookie的方法
2015/06/01 Javascript
js判断当前页面在移动设备还是在PC端中打开
2016/01/06 Javascript
JavaScript操作class和style样式代码详解
2016/02/13 Javascript
Google 地图API资料整理及详细介绍
2016/08/06 Javascript
使用vue编写一个点击数字计时小游戏
2016/08/31 Javascript
Javascript快速实现浏览器系统通知
2017/08/26 Javascript
vue给input file绑定函数获取当前上传的对象完美实现方法
2017/12/15 Javascript
NodeJS 实现多语言的示例代码
2018/09/11 NodeJs
python发送邮件功能实现代码
2016/07/15 Python
python获取网页中所有图片并筛选指定分辨率的方法
2018/03/31 Python
对numpy.append()里的axis的用法详解
2018/06/28 Python
python退出命令是什么?详解python退出方法
2018/12/10 Python
Python后台开发Django的教程详解(启动)
2019/04/08 Python
Python Multiprocessing多进程 使用tqdm显示进度条的实现
2019/08/13 Python
超实用的 30 段 Python 案例
2019/10/10 Python
使用python求解二次规划的问题
2020/02/29 Python
python tkinter之 复选、文本、下拉的实现
2020/03/04 Python
Jupyter加载文件的实现方法
2020/04/14 Python
Ellesse英国官网:意大利高级运动品牌
2019/07/23 全球购物
生产班组长岗位职责
2014/01/05 职场文书
英文升职感谢信
2015/01/23 职场文书
2015年中学总务处工作总结
2015/07/22 职场文书
《刷子李》教学反思
2016/02/20 职场文书
python中出现invalid syntax报错的几种原因分析
2022/02/12 Python