【发布时间】:2014-01-10 17:45:58
【问题描述】:
我正在用 PHP 编写维护脚本。该脚本将大约 100,000 个键值对保存在一个关联数组中,并将一堆其他数据与该数组进行比较。
密钥是 12 或 16 字节的十六进制字符串。
这些值是包含 1-10 个字符串的数组。每个字符串大约 50 个字节。
我通过在循环中使用fgets() 逐行读取文本文件来填充我的数组。
在我敲了大约 44,000 个键之前一切都很好,但在那之后内存使用量突然飙升。
无论我增加多少内存限制(目前我不愿意给它超过 256MB),内存使用量会呈指数增长,直到达到新的限制。这很奇怪!
下面是一张表格,左边是key的数量,右边是内存使用情况。
10000 6668460
20000 12697828
30000 18917768
40000 25045068
41000 25658148
42000 26760304
43000 27350368
44000 27920400
45000 33438520
46000 77800344
47000 114203960
48000 161989660
49000 168419992
50000 206265572
Fatal error: Allowed memory size of 268435456 bytes exhausted
如您所见,在达到 44,000 个键之前,内存使用率一直保持在 620-660 字节/键。之后,内存使用量突然开始增加,直到在 50,000 个键时达到每个键超过 4KB。这很奇怪,因为我的键和值的大小总是相似的。
似乎我在数组中可以拥有的键数量达到了某种内部限制,超过了这个限制,一切都会变得非常低效。
如果我可以保持每个键 620-600 字节的内存使用量(考虑到使用数组的通常开销,这听起来很合理),我的整个数据集应该适合大约 620-600 字节。 64MB 内存,因此当我需要稍后在同一脚本中引用它时可以轻松访问。这是我第一次开始编写脚本时的假设。它是从 CLI 运行的维护脚本,所以偶尔使用 64MB 内存是可以的。
但是如果内存使用量像上面一样不断增加,我将别无选择,只能将键值数据集卸载到外部守护程序,如 Memcached、Redis 或 SQL 数据库,网络开销将大大减慢维护脚本。
到目前为止我尝试了什么:
- 我尝试将二维数组展平为多个一维数组。不走运。
- 我尝试将大数组拆分为多个较小的数组。不走运。
- 我尝试完全不使用数组并将每个键都变成一个单独的变量。不走运。
- 我不能使用
SplFixedArray,因为我的键不是数字(并且不能转换为整数范围内的数字),并且数组需要是可变的。 - 我宁愿不使用 Quickhash、Judy 或任何其他以 C 扩展形式编写的替代数组实现。
- 抱歉,此脚本需要使用 PHP。不要问我为什么...
测试服务器是运行 Ubuntu 12.04 LTS,32 位,PHP 5.3.10-1ubuntu3.9 的虚拟机。
有什么想法吗?
- 这是在较新版本的 PHP 中修复的问题吗?
- 我应该将数据集提供给像 Memcached 这样的外部守护程序吗?
谢谢!
【问题讨论】:
标签: php arrays memory memory-management