我正在用PHP编写维护脚本。该脚本在关联数组中保留大约100,000个键值对,并将一堆其他数据与该数组进行比较。
键是12或16字节的十六进制字符串。
值是包含1-10个字符串的数组。每个字符串大约50个字节。
我通过循环中的fgets()
逐行阅读文本文件来填充我的数组。
一切正常,直到我达到大约44,000个键,但之后内存使用量突然猛增。
无论我增加多少内存限制(目前我还不愿意给它超过256MB),内存使用量会呈指数级增长,直到达到新的限制。这很奇怪!
以下是左侧按键数量和右侧内存使用情况的表格。
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
正如您所看到的,内存使用情况在每个密钥 620-660字节时保持一致,直到我达到44,000个密钥。之后,内存使用量突然开始增加,直到达到每个密钥超过4KB 50,000个密钥。这很奇怪,因为我的键和值的大小总是相似的。
似乎我对数组中可以拥有的键数量有某种内部限制,超出这个限制,这一切都变得非常低效。
如果我可以保持每个键620-600字节的内存使用量(考虑到使用数组的通常开销,这听起来很合理),我的整个数据集应该适合大约。 64MB的内存,因此在我稍后需要在同一个脚本中引用它时可以轻松访问。这是我第一次开始编写脚本时的假设。这是一个从CLI运行的维护脚本,因此可以不时使用64MB的内存。
但如果内存使用率如上所述持续增长,我别无选择,只能将键值数据集卸载到外部守护程序,如Memcached,Redis或SQL数据库,网络开销将大大减慢维护脚本。
到目前为止我尝试了什么:
SplFixedArray
,因为我的键不是数字(并且不能转换为整数范围内的数字),并且数组需要是可变的。测试服务器是运行Ubuntu 12.04 LTS的虚拟机,32位,PHP 5.3.10-1ubuntu3.9。
有什么想法吗?
谢谢!
答案 0 :(得分:2)
我认为这是垃圾收集。在某些时候,你正在使用分配临时空间的操作,然后在努力工作期间无法释放,因此php将耗尽你的记忆而不是真正的目的。
当我遇到这个问题时,我终于得出结论,垃圾只在特定事件中被丢弃,就像退出一个函数一样。所以你应该尝试的是,让你的工作分成几个较小的步骤,让你的变量在它们之间“放松” - 制作一个只能一次完成一千个元素的函数,然后再次调用它继续它停止的地方。
希望这会有所帮助。