【问题标题】:Which one of the following PHP array structure would be using less memory?以下哪一个 PHP 数组结构将使用更少的内存?
【发布时间】:2025-11-27 10:15:02
【问题描述】:

以下哪一项会占用更少的内存?

$myArray = array();
$myArray[1] = array(1,2,3,4,5,6,7,8,9,10);
$myArray[2] = array(1,2,3,4,5,6,7,8,9,10);
$myArray[3] = array(1,2,3,4,5,6,7,8,9,10);

$myArray = array();
$myArray[1] = array(1,2,3);
$myArray[2] = array(1,2,3);
$myArray[3] = array(1,2,3);
$myArray[4] = array(1,2,3);
$myArray[5] = array(1,2,3);
$myArray[6] = array(1,2,3);
$myArray[7] = array(1,2,3);
$myArray[8] = array(1,2,3);
$myArray[9] = array(1,2,3);
$myArray[10] = array(1,2,3);

array(1,2,3,4,5,6,7,8,9,10)array(1,2,3) 在真实场景中可能不会重复。

如果我在 CPU 和内存利用率方面使用其中之一,是否会提高性能。

【问题讨论】:

  • memory_get_usage()
  • 理论上,内存利用率应该是一样的。对于 cpu,它始终取决于您要执行的操作。
  • @Upsilon42 - 在第二种情况下,如果我有更多的键,哈希表的桶大小会影响使用的内存吗?

标签: php arrays php-internals


【解决方案1】:

在第一种情况下,您将创建 4 个数组,总共 33 个元素。在第二种情况下,您将创建 11 个数组,总共 40 个元素。

每个数组都有自己的开销,每个元素也有自己的开销。所以第二种情况占用的内存更多,因为它有更多的数组和更多的元素。

让我们测试一下。

$ php -v
PHP 7.0.2 (cli) (built: Jan  7 2016 10:40:26) ( NTS )
Copyright (c) 1997-2015 The PHP Group
Zend Engine v3.0.0, Copyright (c) 1998-2015 Zend Technologies

测试脚本1:

<?php
$myArray = array();
$myArray[1] = array(1,2,3,4,5,6,7,8,9,10);
$myArray[2] = array(1,2,3,4,5,6,7,8,9,10);
$myArray[3] = array(1,2,3,4,5,6,7,8,9,10);
echo "4 arrays, 33 elements: ", memory_get_usage(), PHP_EOL;

输出:

4 arrays, 33 elements: 354448

测试脚本 2:

<?php
$myArray = array();
$myArray[1] = array(1,2,3);
$myArray[2] = array(1,2,3);
$myArray[3] = array(1,2,3);
$myArray[4] = array(1,2,3);
$myArray[5] = array(1,2,3);
$myArray[6] = array(1,2,3);
$myArray[7] = array(1,2,3);
$myArray[8] = array(1,2,3);
$myArray[9] = array(1,2,3);
$myArray[10] = array(1,2,3);
echo "11 arrays, 40 elements: ", memory_get_usage();

输出:

11 arrays, 40 elements: 358720

确实,第二种情况会消耗更多内存。

也就是说,这个测试具有误导性。第二个脚本更长,因此编译时会产生更多指令,因此即使在执行之前它也会占用更多空间。至少在 PHP 7 中,我们无法测量子数组(array(1,2,3,4,5,6,7,8,9,10)array(1,2,3))占用了多少空间,因为在这种情况下,当您将它们分配给 $myArray 时,它们实际上并没有被创建,而是脚本编译时。因此,即使我们比较脚本开始和结束时的内存使用情况,我们也不会知道它们有多大。另外,所有这些数组都有相同的内容,所以 PHP 可能已经对它们进行了重复数据删除,因此只有一个 array(1,2,3),而不是三个。

不管怎样,这些太小了,不值得担心内存消耗。人们常说“过早的优化是万恶之源”。当您不处理大量数据时,担心您的 PHP 数组占用了多少字节是没有意义的。如果它会让您的代码在没有实际需要的情况下更难阅读和维护,请不要更改它。

【讨论】:

  • 抱歉打扰了,但是搜索 php internals 我找到了你的帖子,想说这里有一个错误。在第一个测试用例中,我们有 3 个元素,每个元素包含 10 个子元素 + [0],这等于 31 个数组元素。在第二种情况下,我们有 10 个元素,其中包含 3 个子元素 + [0],这应该也等于 31 个总数组元素,而不是 40
  • @1000Gbps 没有第 0 个数组元素。而在第二种情况下,每个子数组本身就是一个数组元素,所以你有 10 个子数组加上 10*3 个子数组元素,所以有 40 个元素。不过,我确实在第一个中犯了一个错误:有 33 个元素,而不是 31 个,我不确定我从哪里得到这个数字。
  • 好吧,关于 [0] 的存在你是对的,但为什么 3v4l.org/MR1EL 给第二种情况 30?
  • 5min 编辑规则...为什么我们已经在计算子数组值并证明它们存在时,我们必须将子数组计算为主数组元素?
  • @1000Gbps 我没有说将它们算作“主要”数组元素。无论如何,我计算它们的原因是因为每个数组元素都需要内存。
【解决方案2】:

TL;DR;第二个占用更多内存。


虽然@Andrea 的回答很棒,但我想我会提供更多关于准确计算 PHP 内存的内部方面的见解。因为memory_get_usage() 不能准确地表示 PHP 中特定数据结构消耗的内存量,而是 PHP VM 的一般堆大小,所以很难这样看待。

我很久以前写了一个粗略的 PHP 扩展扩展,名为 Array Analysis PHP,因此可以检查 PHP 数组的内部内存。

警告此扩展可能无法在 PHP 7 上编译,但这是您在 PHP 5 中获得的结果。

$myArray = array();
$myArray[1] = array(1,2,3,4,5,6,7,8,9,10);
$myArray[2] = array(1,2,3,4,5,6,7,8,9,10);
$myArray[3] = array(1,2,3,4,5,6,7,8,9,10);

var_dump(array_size($myArray)); // int(4312)

$myArray = array();
$myArray[1] = array(1,2,3);
$myArray[2] = array(1,2,3);
$myArray[3] = array(1,2,3);
$myArray[4] = array(1,2,3);
$myArray[5] = array(1,2,3);
$myArray[6] = array(1,2,3);
$myArray[7] = array(1,2,3);
$myArray[8] = array(1,2,3);
$myArray[9] = array(1,2,3);
$myArray[10] = array(1,2,3);

var_dump(array_size($myArray)); // int(6272)

由于填充,这些值在您的系统上可能会或可能不会略有不同,但它是数组大小的相当准确的表示,并且比您在memory_get_usage() 中看到的要少得多,因为此扩展明确挖掘进入构成 PHP 内存中数组的内部结构,并逐个检查它以找出它的大小。

【讨论】:

    【解决方案3】:

    你可以这样检查

    echo memory_get_usage() . "\n"; // 154432
    
    $myArray = array();
    $myArray[1] = array(1,2,3);
    $myArray[2] = array(1,2,3);
    $myArray[3] = array(1,2,3);
    $myArray[4] = array(1,2,3);
    $myArray[5] = array(1,2,3);
    $myArray[6] = array(1,2,3);
    $myArray[7] = array(1,2,3);
    $myArray[8] = array(1,2,3);
    $myArray[9] = array(1,2,3);
    $myArray[10] = array(1,2,3);
    
    echo memory_get_usage() . "\n"; // 157360
    

    【讨论】: