在PHP中需要一个类似于数组的结构,内存使用量最少

Ale*_*ler 65 php arrays memory-management out-of-memory

在我的PHP脚本中,我需要创建一个> 600k整数的数组.不幸的是,我的web服务器memory_limit设置为32M,所以在初始化数组时,脚本会中止消息

致命错误:8/home/www/myaccount/html/mem_test.php中允许的内存大小为33554432字节(试图分配71个字节)

我知道PHP不会将数组值存储为普通整数,而是存储为比普通整数值大得多的z值(在我的64位系统上为8个字节).我写了一个小脚本来估计每个数组条目使用多少内存,事实证明,它恰好是128个字节.128!我需要> 73M才能存储阵列.不幸的是,网络服务器不在我的控制之下,所以我无法增加memory_limit.

我的问题是,在PHP中是否有可能创建一个使用更少内存的类似数组的结构.我不需要这种结构是关联的(普通的索引访问就足够了).它也不需要动态调整大小 - 我确切知道数组的大小.此外,所有元素都是相同的类型.就像一个好旧的C阵列.


编辑: 所以deceze的解决方案与32位整数一起开箱即用.但即使您使用的是64位系统,pack()似乎也不支持64位整数.为了在我的数组中使用64位整数,我应用了一些位操作.也许下面的片段对某些人有帮助:

function push_back(&$storage, $value)
{
    // split the 64-bit value into two 32-bit chunks, then pass these to pack().
    $storage .= pack('ll', ($value>>32), $value);
}

function get(&$storage, $idx)
{
    // read two 32-bit chunks from $storage and glue them back together.
    return (current(unpack('l', substr($storage, $idx * 8, 4)))<<32 |
            current(unpack('l', substr($storage, $idx * 8+4, 4))));
}
Run Code Online (Sandbox Code Playgroud)

dec*_*eze 59

您将获得的内存效率最高的可能是将所有内容存储在一个字符串中,以二进制形式打包,并使用手动索引.

$storage = '';

$storage .= pack('l', 42);

// ...

// get 10th entry
$int = current(unpack('l', substr($storage, 9 * 4, 4)));
Run Code Online (Sandbox Code Playgroud)

如果"阵列"初始化可以一举完成并且您只是从结构中读取,那么这是可行的.如果你需要大量附加到字符串,这将变得非常低效.即便如此,也可以使用资源句柄来完成:

$storage = fopen('php://memory', 'r+');
fwrite($storage, pack('l', 42));
...
Run Code Online (Sandbox Code Playgroud)

这非常有效.然后,您可以将此缓冲区读回变量并将其用作字符串,或者您可以继续使用资源和fseek.

  • 从PHP pack()手册"在整数类型具有64位大小的系统中,浮点数很可能没有足够大的尾数来保存该值而不会丢失精度.如果这些系统也具有本机64位C int类型(大多数类UNIX系统没有),在上限范围内使用I pack格式的唯一方法是创建整数负值,其字节表示与所需的无符号值相同." 因此,即使php是64位编译它似乎仍然只支持32位正确的包 (2认同)

Rya*_*yan 28

PHP朱迪阵列将使用显著较少的内存比标准PHP阵列,并且一个SplFixedArray.

我引用"使用常规PHP数组数据结构的100万个条目的数组需要200MB.SplFixedArray使用大约90兆字节.Judy使用8兆.权衡是性能,Judy花费大约两倍于常规php数组实现的时间."

  • 但这是一个扩展,如果他没有增加mem_limit的权限,那么他将无法访问安装扩展,尽管这对其他人来说是一个很好的解决方案 (11认同)
  • 对于那些可能会查看我的问题的人来说,这仍然是一个很好的答案. (9认同)

Dys*_*mus 11

您可以尝试使用SplFixedArray,它更快,占用更少的内存(文档评论说减少约30%).在这里这里测试.


RJD*_*D22 11

如果可能,您可以使用对象.这些通常比数组使用更少的内存.此外SplFixedArray是一个不错的选择.

但这实际上取决于您需要执行的实现.如果你需要一个函数来返回一个数组并使用PHP 5.5.您可以使用生成器yield来回流数组.


dke*_*ner 5

使用字符串 - 这就是我要做的.将它存储在固定偏移量的字符串中(我猜是16或20位应该这样做吗?)并使用substr来获得所需的偏移量.超快速写入/读取,超级简单,600,000整数只需要~12M即可存储.

base_convert() - 如果你需要更紧凑但更省力的东西,将你的整数转换为base-36而不是base-10; 在这种情况下,一个14位数字将存储在9个字母数字字符中.你需要制作2个64位的整数,但我确信这不是问题.(我将它们拆分为9位数块,转换为你提供6-char版本.)

pack()/ unpack() - 二进制打包是一回事,效率更高一些.如果没有其他工作,请使用它; 分割你的数字,使它们适合两个32位的片段.