在PHP应用运行的过程中,文件描述符是系统分配给进程用于访问文件、套接字等资源的标识,如果进程打开的文件描述符数量持续升高,很可能存在文件句柄未正确关闭的问题,因此准确获取当前PHP进程打开的文件描述符数量对排查资源泄漏问题非常重要。

什么是文件描述符
文件描述符是Unix、Linux等系统中用于标识已打开文件的整数,每个进程都有独立的文件描述符表,系统默认会为进程预分配0、1、2三个标准描述符,分别对应标准输入、标准输出、标准错误。PHP中打开文件、建立网络连接等操作都会消耗文件描述符。
方法一:读取proc文件系统
Linux系统中,每个进程的信息都存放在/proc/[pid]/fd目录下,该目录下的每一个条目都对应进程打开的一个文件描述符,因此统计该目录下的条目数量就可以得到当前进程打开的文件描述符总数。
首先我们需要获取当前PHP进程的PID,可以通过getmypid()函数获取,之后读取对应fd目录下的内容统计数量即可,示例代码如下:
<?php
// 获取当前PHP进程的PID
$pid = getmypid();
// 拼接fd目录路径
$fdDir = "/proc/{$pid}/fd";
// 判断目录是否存在
if (is_dir($fdDir)) {
// 打开目录句柄
$dh = opendir($fdDir);
$fdCount = 0;
// 遍历目录统计条目数量
while (readdir($dh) !== false) {
$fdCount++;
}
closedir($dh);
// 减去.和..两个特殊目录条目
$fdCount -= 2;
echo "当前进程打开的文件描述符数量为:{$fdCount}";
} else {
echo "当前系统不支持proc文件系统,无法使用该方法统计";
}
这种方法的优点是无需依赖额外命令,只要系统支持proc文件系统就可以使用,统计结果准确,但是需要注意如果进程没有权限访问/proc/[pid]/fd目录,会导致统计失败。
方法二:使用lsof命令统计
lsof是Linux系统中用于列出当前系统打开文件的工具,也可以指定PID来查看对应进程打开的所有文件描述符,通过统计输出结果的数量就可以得到文件描述符总数。
我们可以通过exec()或者shell_exec()函数调用lsof命令,然后处理输出结果,示例代码如下:
<?php
// 获取当前进程PID
$pid = getmypid();
// 执行lsof命令,只输出该进程的文件描述符信息
$output = shell_exec("lsof -p {$pid} 2>/dev/null");
if ($output !== null) {
// 按行分割输出结果
$lines = explode("n", $output);
// 减去表头行
$fdCount = count($lines) - 1;
// 处理空行情况
if ($fdCount < 0) {
$fdCount = 0;
}
echo "当前进程打开的文件描述符数量为:{$fdCount}";
} else {
echo "执行lsof命令失败,可能当前环境没有安装lsof工具";
}
这种方法的兼容性稍差,需要系统安装lsof工具,并且PHP需要有执行shell命令的权限,但是lsof可以输出更详细的文件描述符对应的资源信息,方便进一步排查问题。
方法三:通过getrusage获取资源使用情况
PHP的getrusage()函数可以获取当前进程的资源使用情况,其中ru_nvcsw等字段不直接对应文件描述符数量,但部分系统下可以通过其他方式结合,不过这种方法的局限性较大,不同系统下的返回值差异明显,一般不推荐作为首选方法,仅作为补充思路。
不同方法的对比
我们可以通过下表对比三种方法的特性:
| 方法 | 依赖条件 | 准确性 | 适用场景 |
|---|---|---|---|
| 读取proc文件系统 | 系统支持proc,进程有目录访问权限 | 高 | Linux环境,无额外命令依赖的场景 |
| lsof命令统计 | 系统安装lsof,PHP有shell执行权限 | 高 | 需要详细文件描述符信息的排查场景 |
| getrusage函数 | 系统支持对应资源字段 | 低 | 仅作为补充,不推荐常规使用 |
注意事项
- 统计文件描述符数量时,要注意排除统计过程中的临时打开的描述符,比如打开目录、执行命令时临时创建的描述符,避免结果偏高。
- 如果PHP进程运行在容器环境中,需要确保容器内有对应的proc文件系统挂载或者lsof工具可用。
- 频繁统计文件描述符数量可能会对进程性能有轻微影响,不建议在高并发请求中频繁调用。
通过上述几种方法,开发者可以根据自身的运行环境选择合适的方式,准确获取当前PHP进程打开的文件描述符数量,及时发现和处理文件句柄泄漏的问题。