PHP数组中的内存优化
我使用的是一个大数组,它是一个高度图,1024x1024,当然,我的内存有限。在我的测试机器中,如果我愿意的话,我可以将内存限制提高到1gb,但是在我只有256 ram的小型VPS中,这不是一个选项 我一直在stack和google中搜索,发现了几个“好吧,你使用PHP不是因为内存效率,放弃它,用c++重写吧。”老实说,没关系,我知道PHP喜欢内存 但是,当深入了解PHP内存管理时,我并没有发现每种数据类型消耗的内存是什么。或者,如果转换到另一种类型的数据可以减少内存消耗 我发现的唯一“优化”技术就是取消变量和数组的设置,就是这样PHP数组中的内存优化,php,arrays,memory-management,Php,Arrays,Memory Management,我使用的是一个大数组,它是一个高度图,1024x1024,当然,我的内存有限。在我的测试机器中,如果我愿意的话,我可以将内存限制提高到1gb,但是在我只有256 ram的小型VPS中,这不是一个选项 我一直在stack和google中搜索,发现了几个“好吧,你使用PHP不是因为内存效率,放弃它,用c++重写吧。”老实说,没关系,我知道PHP喜欢内存 但是,当深入了解PHP内存管理时,我并没有发现每种数据类型消耗的内存是什么。或者,如果转换到另一种类型的数据可以减少内存消耗 我发现的唯一“优化”技
使用一些PHP解析器将代码转换为C++可以解决这个问题?
谢谢 如果需要真正的索引数组,请使用。它使用更少的内存。另外,PHP5.3还有一个更好的垃圾收集器 除此之外,PHP将使用比更仔细编写的C/C++等效程序更多的内存 1024x1024整数数组的内存使用情况:
- 标准阵列:218756848
- SplFixedArray:92914208
memory\u get\u peak\u usage()测量
这里的内存大约只有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
压缩数组使用本机64位整数(仅压缩7个字节以避免处理有符号数据),压缩字符串使用ord
和chr
。显然,实现细节和计算机规格会对事情产生一些影响,但我希望您能得到类似的结果
因此,虽然数组速度提高了6倍,但它也使用了125倍的内存作为下一个最佳选择:压缩字符串。显然,如果内存不足,速度是不相关的。(当我在没有ArrayAccess
类的情况下直接使用压缩字符串时,它们只比本机数组慢3倍。)
简言之,总而言之,如果速度值得关注,我会使用纯PHP以外的东西来处理这些数据。除了评论中公认的答案和建议之外,我还想提出一些建议
快速测试显示了有趣的结果。使用常规PHP数组数据结构的具有100万个条目的数组需要约200 MB。SplFixedArray使用大约90兆字节。朱迪用了8兆欧。折衷是在性能上,Judy花费的时间大约是常规php数组实现时间的两倍。晚了一点,但是如果您有一个多维数组,那么在将整个数组存储为json时,可以节省大量RAM
$array = [];
$data = [];
$data["a"] = "hello";
$data["b"] = "world";
要存储此阵列,只需使用:
$array[] = json_encode($data);
而不是
$array[] = $data;
如果您想拿回arrry,只需使用以下方法:
$myData = json_decode($array[0], true);
我有一个275000台的大阵列,节省了大约36%的内存消耗
编辑:
在压缩json字符串时,我找到了一种更好的方法:
$array[] = gzencode(json_encode($data));
并在需要时将其解压缩:
$myData = json_decode(gzdecode($array[0], true));
这为我节省了近75%的RAM峰值使用量。在PHP中,数组确实需要大量内存(因为它们实际上是字典)。如果你可以放弃一些(很多!)的速度,你也可以,我想2D结构也是如此。但也许你真的想调查一下,你需要削减多少内存?正如您所读到的,在内存管理方面,在PHP中几乎没有什么可以做的。你可以进行一些“优化”,但可能没有什么能像你所需要的那样减少。PHP中的每个变量都有与之相关的开销。不仅要存储变量的值,还要存储变量的名称、类型等。。。即使是一个简单的$x[1]=2
后面有大量的额外内容。@mario我想知道为什么链接的帖子停止了十六进制编码,而没有直接使用字符串的完整字节。看起来一点数学其实可以更快。。。但是我不使用PHP(它不会考虑有效的多字节序列等等:-)@pst:我确实有另一个版本使用pack()
处理二进制字符串。但这并不是真的更快;只需节省两倍的内存。(在PHP中只能伪造这么多;)+1此外,模拟数组索引和使用打包可以进一步减少内存使用量(如果适用)。例如,如果每个高度映射值仅为8位,则当压缩为32位(或64位,取决于PHP位数)时,内存使用量应大大减少。效率的确切增益因有效负载大小/利用率与所用PHP值的值维护开销而不同。(我认为每个整数值有4个字节的“开销”,但我不完全确定。)显然有超过4个字节的开销。。。建议仅对于一个微不足道的值,它可能需要36(或x64上的72)字节以上。这表明打包是非常有益的(在内存使用方面)。假设8位输入和32位arch,如果打包,4个值将占用约36字节而不是约144字节,而在x64机器上,8个值将占用约72字节而不是约576字节!(哎呀!)所以,最后。。。通过打包,8位值被摊销到~9字节,用于即时估算9MB的对象开销/数据,不包括包含在数组本身中所需的内存等——将公布的数字四分之一的总使用量约为22.5MB。(这种打包可能看起来过于优化,但考虑到目标限制为256MB RAM…-)@pst,我添加了一些关于将数据打包成字符串的内容。当处理8位整数(可能是高度映射)时,字符串整数数组的大小基本上与C等价物的大小相同。当然,速度会比本机整数差得多。@konforce Packing in a PHP integral value:)对于许多操作(仅一个ma),速度应该接近非压缩
$array[] = gzencode(json_encode($data));
$myData = json_decode(gzdecode($array[0], true));