我有一个需要418 MB进行base64编码的文件,但是我不断收到内存限制错误。我已经在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的内存。是否将x86版本的php硬编码为仅允许小于1GB?如果没有,当我只需要消耗1GB但有2GB的限制时,为什么会出现PHP Fatal error: Out of memory
错误?
答案 0 :(得分:2)
从理论上讲,您应该能够在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);
答案 1 :(得分:0)
检查是否有足够的内存。如果您只有<1gb的可用系统内存(或其他虚拟内存限制,例如容器内存限制),则更改限制和更改可寻址内存(64位)的数量将无关紧要