PHP x86 内存限制

PHP x86 Memory Limit

我有一个文件需要进行 base64 编码,该文件大小为 418 MB,但我一直收到内存限制错误。我已经在 php.ini 中设置了 memory_limit=2048M 但我仍然无法将它作为 base64 字符串读入内存,x86 CLI 版本为 PHP.

PHP脚本

<?php

echo "\r\n";
echo "\r\nMemory Usage\r\n" . memory_get_usage(false) . " Bytes\r\nReal " . memory_get_usage(true) . " Bytes\r\n";
echo "\r\nPeak Memory Usage\r\n" . memory_get_peak_usage(false). " Bytes\r\nReal " . memory_get_peak_usage(true) . " Bytes\r\n";
echo "\r\nMemory Limit\r\n" . ini_get('memory_limit') . "\r\n";

$file = file_get_contents('C:\Path\To\File');

echo "\r\n";
echo "\r\nMemory Usage\r\n" . memory_get_usage(false) . " Bytes\r\nReal " . memory_get_usage(true) . " Bytes\r\n";
echo "\r\nPeak Memory Usage\r\n" . memory_get_peak_usage(false). " Bytes\r\nReal " . memory_get_peak_usage(true) . " Bytes\r\n";
echo "\r\nMemory Limit\r\n" . ini_get('memory_limit') . "\r\n";

$encodedFile = base64_encode($file);

echo "\r\n";
echo "\r\nMemory Usage\r\n" . memory_get_usage(false) . " Bytes\r\nReal " . memory_get_usage(true) . " Bytes\r\n";
echo "\r\nPeak Memory Usage\r\n" . memory_get_peak_usage(false). " Bytes\r\nReal " . memory_get_peak_usage(true) . " Bytes\r\n";
echo "\r\nMemory Limit\r\n" . ini_get('memory_limit') . "\r\n";

?>

运行 该脚本生成以下内容。

PS C:\> php .\MemoryIssueTest.php


Memory Usage
382184 Bytes
Real 2097152 Bytes

Peak Memory Usage
422256 Bytes
Real 2097152 Bytes

Memory Limit
2048M


Memory Usage
447075680 Bytes
Real 448790528 Bytes

Peak Memory Usage
447084280 Bytes
Real 448790528 Bytes

Memory Limit
2048M

VirtualAlloc() failed: [0x00000008] Not enough memory resources are available to process this command.


VirtualAlloc() failed: [0x00000008] Not enough memory resources are available to process this command.

PHP Fatal error:  Out of memory (allocated 448790528) (tried to allocate 593015064 bytes) in C:\MemoryIssueTest.php on line 14
PHP Stack trace:
PHP   1. {main}() C:\MemoryIssueTest.php:0
PHP   2. base64_encode() C:\MemoryIssueTest.php:14

Fatal error: Out of memory (allocated 448790528) (tried to allocate 593015064 bytes) in C:\MemoryIssueTest.php on line 14

Call Stack:
    0.4046     382152   1. {main}() C:\MemoryIssueTest.php:0
   33.4669  447075680   2. base64_encode() C:\MemoryIssueTest.php:14

升级到 64 位版本后 PHP 我从同一个脚本中得到以下结果。

PS C:\> php .\MemoryIssueTest.php


Memory Usage
402088 Bytes
Real 2097152 Bytes

Peak Memory Usage
444160 Bytes
Real 2097152 Bytes

Memory Limit
2048M


Memory Usage
440804144 Bytes
Real 442499072 Bytes

Peak Memory Usage
440812824 Bytes
Real 442499072 Bytes

Memory Limit
2048M


Memory Usage
1025909576 Bytes
Real 1027604480 Bytes

Peak Memory Usage
1025909760 Bytes
Real 1027604480 Bytes

Memory Limit
2048M

据我了解,x86 应用程序应该能够消耗超过 1GB 的内存。 php 的 x86 版本是否硬编码为仅允许小于 1GB?如果不是,为什么我只需要消耗 1GB 但我有 2GB 限制时会收到 PHP Fatal error: Out of memory 错误?

理论上,您应该能够在 Windows 上为 x86 进程分配最多 2GB 的内存。但是,对于您可以分配的数量还有其他限制。至关重要的是:可用地址 space 中的内存碎片。由于 base64_encode 一次性分配了所需的所有内存,因此您需要足够的 连续 地址 space 来对整个字符串进行编码。您更有可能对 64 位地址 space 感到厌倦,这就是为什么 PHP 的 64 位版本运行得很好。

有关此答案的更多信息:Java maximum memory on Windows XP

附录:在我的测试中,我只能分配比你多一点的地址,但更小的地址分配让我更接近 2GB 的限制。

附录 2:如果您绝对需要使用 32 位版本并且正在编码到文件中,您可以通过编码为 3 字节的倍数来解决这个问题,然后您可以将它们连接起来。

// Example, from memory string to file.
$current_position = 0;
$length = strlen($file);
$outputfile = fopen('testoutput.txt', 'w');
while($current_position < $length) {
  fwrite($outputfile, base64_encode(substr($file, $current_position, 60000)));
  $current_position += 60000;
}
fclose($outputfile);

或者一路走下去,从一个文件到另一个文件,分配的内存很少:

$inputfile = fopen('test.mp4', 'rb');
$outputfile = fopen('testoutput2.txt', 'w');
while( ($str = fread($inputfile, 61440)) !== false ) {
  if($str === '') {
    break;
  }
  fwrite($outputfile, base64_encode($str));
  $current_position += 61440;
}
fclose($outputfile);

检查您是否有足够的内存。如果您只有 <1gb 的可用系统内存(或容器内存限制等其他虚拟内存限制),更改限制和可寻址内存(64 位)的数量无关紧要