我有一个php脚本,它读入一个文本文件并对文件中与指定正则表达式匹配的所有行进行计数。到目前为止,该脚本运行良好,因为它对超过2GB的文件进行了分析。
实际上在segfault之前,我最初收到PHP致命错误:PHP致命错误:允许的内存大小为1073741824字节耗尽(试图分配2223941409字节)。
要解决此问题,我将此行添加到我的脚本中:ini_set('memory_limit','4G'); 这修复了内存大小耗尽的错误,但我现在得到了fread的段错误。
这是脚本的精简工作版本,它将显示错误:
#!/usr/bin/php
<?php
ini_set('memory_limit', '4G');
$file = $argv[1];
$fh = fopen($file, 'r');
$fsize = filesize($file);
print("SIZE: ".$fsize."\n" );
$myData = fread($fh, $fsize);
print("Got passed fread!\n");
fclose($fh);
preg_match_all( '/Z\t/', $myData, $sArray );
$scount = count($sArray,COUNT_RECURSIVE);
print("COUNT: ".$scount."\n");
?>
示例输出:
$ runtest.php testfile.txt
SIZE: 2223941408
Segmentation fault (core dumped)
其他信息:
操作系统:CentOS版本6.7(最终版)x86_64
PHP 5.3.3(cli)(内置:2015年7月9日17:39:00)64位
答案 0 :(得分:0)
Hi 2GB意味着PHP中存在一些内部32位限制。你在运行32位PHP吗?
还有另一种解决方案。您可以使用PHP调用的shell命令以非常小的内存开销执行此操作。使用的内存不会超过几MB,因为grep和wc只将文件的一部分加载到内存中。
$lines = shell_exec("grep 'Z\t' $file | wc --lines");
grep:使用正则表达式搜索文件的命令
wc:命令,返回单词/行/字符数
答案 1 :(得分:0)
您可能正在使用32位PHP发行版。在这种架构下,PHP进程无法分配超过2 GB的RAM。在实践中,上限接近1GB而不是2GB - 解释器在达到2 GB限制之前崩溃。此外,整数变量不能大于PHP_INT_MAX,在32个版本中,它小到2,147,483,647(2 32 -1)。
这突出了代码中的两个问题:
$fsize = filesize($file);
... will not work如果文件大小超过PHP_INT_MAX
。
由于PHP的整数类型已签名且许多平台使用32位整数,因此某些文件系统函数可能会为大于2GB的文件返回意外结果。
$myData = fread($fh, $fsize);
...对于大文件会崩溃,因为你在内存中加载完整的文件内容,然后进行额外的处理,可能会占用更多的内存。
您最好重新设计算法并以小块(fread()
擅长的任务)读取文件。计算两个字符的子串的出现应该只需要几KB的RAM。
这是一种假设单字节编码的可能方法(正如您的代码所做的那样):
// Ridiculously small value for illustration purposes, set to something bigger for better performance
define('CHUNK_SIZE', 4);
$fsize = $scount = 0;
$fh = fopen($file, 'r');
$possible_pending_match = false;
while (!feof($fh)) {
$chunk = fread($fh, CHUNK_SIZE);
$fsize += strlen($chunk);
$scount += substr_count($chunk, "Z\t");
if ($possible_pending_match && $chunk[0]==="\t") {
$scount++;
}
$possible_pending_match = substr($chunk, -1)==='Z';
}
print("SIZE: ".$fsize."\n" );
print("COUNT: ".$scount."\n");
print("MEMORY: ".memory_get_peak_usage(true)." bytes\n");
您需要向$scount
添加1以获得与您的代码相同的结果,因为没有明显的原因会计算一个额外的项目 - 这感觉就像一个错误,但我不知道规格。< / p>