PHP x86 内存限制

4

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

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致命错误:内存不足”的错误?


如果将 memory_limit 设置为 -1,让 x86 版本使用所需的内存,它是否能正确运行? - Dave
你打算对这个经过base64编码的文件做什么? - Stephanie Temple
@StephanieTemple 将其发送到 Elasticsearch 进行索引。 - Matthew Goheen
2个回答

3
从理论上讲,在Windows上,x86进程应该能够分配多达2GB的内存。但是,您可以分配的内存量受其他限制。最关键的是:可用地址空间中的内存碎片。由于base64_encode一次性分配其所需的内存,因此您需要足够的连续地址空间来编码整个字符串。使用64位地址空间,您更有可能拥有足够的地址空间,这就是为什么64位版本的PHP运行良好的原因。
在这个答案中,提供了更多信息: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);

0

请检查您的内存是否足够。如果您只有不到1GB的系统内存(或其他虚拟内存限制,如容器内存限制),那么更改限制和更改可寻址内存量(64位)都没有意义。


我的机器有16GB的RAM,根据资源监视器,在测试时只使用了约3GB的内存。 - Matthew Goheen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接