PHP数组操作时内存使用突然增加

标签 php arrays memory memory-management

我正在用 PHP 编写维护脚本。该脚本在关联数组中保留了大约 100,000 个键值对,并将一堆其他数据与该数组进行比较。

key 是 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 个键。之后,内存使用量突然开始增加,直到达到 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 会毫无意义地耗尽您的内存。

当我面对这个问题时,我终于得出结论:垃圾仅在特定事件中被丢弃,例如退出函数。因此,您应该尝试的是,分几个较小的步骤完成这项工作,并让变量在它们之间“放松”——创建一个一次只执行一千个元素的函数,然后再次调用它以从中断的地方继续。

希望这有帮助。

关于PHP数组操作时内存使用突然增加,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20727755/

相关文章:

c++ - 按下回车键时停止将值输入数组

arrays - 将 Postgres ARRAY 中的 {NULL} 更改为 NULL

c - 添加新功能会导致内存损坏

hadoop - 当使用更多节点时,Hadoop无法创建足够的容器

php - 在 Linux 或其他支持 UTF-8 的驱动程序上安装 SQLSRV 驱动程序?

php - GTFS 实时 php

php - 使用PHP在mysql数据库中上传图片

php - 使用 Laravel 5.6 加载用户设置

java - Java 中的有序 JSON 转换,读取 JSONObjects 的 JSONArray

c++ - 使用 Qt/C++ 从单独的线程发出对象时如何避免复制?