致命错误-打开的文件太多


Fatal Error - Too many open files

我试图在我的新机器中运行PHPUnit测试,但我得到了这个错误:

PHP致命错误:未捕获异常"UnexpectedValueException",消息为"RecursiveDirectoryTerator::__construct(/usr/lib/PHP/pear/File/Iterator):无法打开/usr/lib/PHP/pear/File/Iterator/Factory.PHP:114 中的dir:打开的文件太多"

旧机器上的相同代码运行良好。。。

新机器环境:PHP版本:PHP 5.3.21(cli)旧版本:PHP 5.3.14

PHPUnit每次输出:

................EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE 65 / 66 ( 98%)
E
Time: 34 seconds, Memory: 438.50Mb
There were 50 errors:
1) XXXXXXXXXXX
PHP Fatal error:  Uncaught exception 'UnexpectedValueException' with message 'RecursiveDirectoryIterator::__construct(/usr/lib/php/pear/File/Iterator): failed to open dir: Too many open files' in /usr/lib/php/pear/File/Iterator/Factory.php:114

这可能是对运行代码的服务器的限制。每个操作系统只允许一定数量的打开文件/句柄/套接字。当服务器被虚拟化时,这个限制通常会进一步降低。在Linux服务器上,您可以使用ulimit -n检查当前限制,如果您具有root访问权限,则可以使用相同的命令增加限制。我想Windows服务器也有一种方法。否则,你对此无能为力(除了要求你的房东或管理员增加它)。

更多可配置限制:

/etc/security/limits.conf 的变化

soft nofile 1024
hard nofile 65535

将ulimit增加ulimit -n 65535echo 65535 > /proc/sys/fs/file-max 或在/etc/sysctl.conf:中

fs.file-max=65535

如何提高文件打开限制(Linux或Max OS):

ulimit -n 10000

解决了phpunit或/和phpdbgWarning: Uncaught ErrorException: require([..file]): failed to open stream: Too many open files in [...] 的问题

在php中,在执行之前,请尝试此

exec('ulimit -S -n 2048');

从睡眠模式"唤醒"我的电脑后,我遇到了这个问题。

重新启动php-fpm像这样修复了它。经典关闭它&重复使用解决方案。

sudo /etc/init.d/php-fpm restart

我认为这可能与我最近添加到php中的xdebug有关。

以后不要存储DirectoryTerator对象;当您存储的文件超过操作系统限制(通常为256或1024)时,会出现一个错误,称为"打开的文件太多"。

例如,如果目录中的文件太多,这将产生错误:

<?php 
$files = array(); 
foreach (new DirectoryIterator('myDir') as $file) { 
    $files[] = $file; 
} 
?>

据推测,这种方法也是内存密集型的。

来源:http://php.net/manual/pt_BR/directoryiterator.construct.php#87425

我注意到,在PHP中,当您忘记在闭包中包装某些内容时,会发生这种情况。仔细查看您最近的diff,您可能会了解到这一点(在我的案例中,我在Laravel PHP单元工厂中引用了$faker,而没有关闭。

我在Http池中遇到了这个错误,我在池中添加了太多URL(大约2000个URL)。

我不得不把url分成更小的批,错误就停止了。

我认为这就是Guzzle Pool的工作原理,它不会在整个游泳池完成之前关闭卷曲连接。

示例

$responses = Http::pool(function (Pool $pool) use ($chunk) {
    return collect($chunk)->map(fn($url) => $pool->get($url));
});

成为:

collect($urls)
    ->chunk(25)
    ->each(function ($chunk) {
        $responses = Http::pool(function (Pool $pool) use ($chunk) {
            return collect($chunk)->map(fn($url) => $pool->get($url));
        });
    });

Http函数是Laravel使用GuzzleHttpClient的包装函数。https://laravel.com/docs/9.x/http-client

在服务器debian上,您也可以转到

/etc/php/php7.xx/fpm/pool.d/www.conf

rlimit_files=10000

/etc/init.d/php7.xx restart

也许,文件/etc/init.d/phpx.x-fpm有一些错误。让我们重新启动它:

sudo /etc/init.d/php7.2-fpm restart

每次Redis库PHP试图加载时,我都会遇到这个错误,但这是由我最初没有真正想到的事情引起的。当我的程序运行了一段时间,做了一个重复的过程时,我不断地得到这个错误。我发现我打开了一个cURL会话($ch = new curl_init(...)),它在类的析构函数中被关闭,但该析构函数从未被调用。我解决了这个问题,打开太多文件的错误消失了。