PHP数组中的内存优化

Gab*_*lla 25 php arrays memory-management

我正在使用一个大型数组,这是一个高度图,1024x1024,当然,我坚持内存限制.在我的测试机器中,如果我愿意,我可以将内存限制增加到1GB,但在我只有256内存的微小VPS中,它不是一个选项.

我一直在堆栈和谷歌搜索,并发现几个"好吧,你使用PHP不是因为内存效率,抛弃它并在c ++中重写"老实说,这没关系,我认识PHP喜欢内存.

但是,当在PHP内存管理中挖掘更多时,我没有发现每种数据类型消耗的内存.或者,如果转换为其他类型的数据可以减少mem消耗.

我发现唯一的"优化"技术是取消设置变量和数组,就是这样.

使用一些PHP解析器将代码转换为c ++可以解决问题吗?

谢谢!

Mat*_*hew 48

如果需要真正的索引数组,请使用SplFixedArray.它使用更少的内存.此外,PHP 5.3有一个更好的垃圾收集器.

除此之外,PHP将使用更多内存而不是更精心编写的C/C++等价物.

1024x1024整数数组的内存使用情况:

  • 标准阵列:218,756,848
  • SplFixedArray:92,914,208

通过测量 memory_get_peak_usage()

$array = new SplFixedArray(1024 * 1024); // array();
for ($i = 0; $i < 1024 * 1024; ++$i)
  $array[$i] = 0;

echo memory_get_peak_usage();
Run Code Online (Sandbox Code Playgroud)

请注意,使用64位整数的C中的相同数组将是8M.

正如其他人所建议的那样,您可以将数据打包成字符串.这会慢一些,但很多更多的内存效率.如果使用8位值,这非常简单:

$x = str_repeat(chr(0), 1024*1024);
$x[$i] = chr($v & 0xff); // store value $v into $x[$i]
$v = ord($x[$i]);        // get value $v from $x[$i]
Run Code Online (Sandbox Code Playgroud)

这里的内存只有大约1.5MB(也就是说,只考虑整数字符串数组考虑PHP的整个开销).

为了它的乐趣,我创建了一个简单的基准,创建1024x1024 8位整数,然后循环它们一次.打包版本全部使用,ArrayAccess以便用户代码看起来相同.

                   mem    write   read
array              218M   0.589s  0.176s
packed array       32.7M  1.85s   1.13s
packed spl array   13.8M  1.91s   1.18s
packed string      1.72M  1.11s   1.08s
Run Code Online (Sandbox Code Playgroud)

填充阵列中使用本机64位整数(只包装7个字节,以避免处理签名的数据)和所使用的填充字符串ordchr.显然,实现细节和计算机规格会对事情产生一些影响,但我希望你能得到类似的结果.

因此,尽管阵列速度提高了6倍,但它仍然使用了125倍的内存作为下一个最佳选择:打包字符串.显然,如果你的内存不足,速度是无关紧要的.(当我在没有ArrayAccess类的情况下直接使用压缩字符串时,它们只比原生数组慢3倍.)

简而言之,总而言之,如果速度有任何问题,我会使用纯PHP之外的其他东西来处理这些数据.


N.B*_*.B. 11

除了评论中接受的答案和建议之外,我还想建议PHP Judy数组实现.

快速测试显示有趣的结果.使用常规PHP数组数据结构的100万个条目的数组大约需要200 MB.SplFixedArray使用大约90兆字节.朱迪使用8兆.权衡取决于性能,Judy占用常规php数组实现时间的两倍.


Mar*_*rco 6

虽然有点晚了,但如果你有一个多维数组,当你将完整的数组存储为 json 时,可以节省大量 RAM。

$array = [];

$data = [];
$data["a"] = "hello";
$data["b"] = "world";
Run Code Online (Sandbox Code Playgroud)

要存储这个数组只需使用:

$array[] = json_encode($data);
Run Code Online (Sandbox Code Playgroud)

代替

$array[] = $data;
Run Code Online (Sandbox Code Playgroud)

如果你想取回数组,只需使用类似以下内容:

$myData = json_decode($array[0], true);
Run Code Online (Sandbox Code Playgroud)

我有一个包含 275.000 组的大数组,节省了大约 36% 的 RAM 消耗。

编辑:当你压缩 json 字符串时,我找到了一种更好的方法:

$array[] = gzencode(json_encode($data));
Run Code Online (Sandbox Code Playgroud)

并在需要时解压缩:

$myData = json_decode(gzdecode($array[0], true));
Run Code Online (Sandbox Code Playgroud)

这为我节省了近 75% 的 RAM 峰值使用量。