前言
本篇将结合代码,着重解析文件描述符的回收与重用。
关于文件描述符分配机制部分的介绍可以看前文。
1. 文件描述符的回收与重用
当关闭一个文件描述符(如 close(clientfd)
)时,内核会将其标记为可用状态,供后续分配使用。文件描述符的重用行为取决于以下因素:
立即重用:如果关闭文件描述符后立即重新分配,内核可能会优先分配刚刚释放的文件描述符。
延迟重用:如果关闭文件描述符后等待一段时间再重新分配,内核可能会分配其他可用的文件描述符。
2. 代码演示与运行结果
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int main() {
int fd1 = open("file1.txt", O_CREAT | O_RDWR, 0644);
int fd2 = open("file2.txt", O_CREAT | O_RDWR, 0644);
int fd3 = open("file3.txt", O_CREAT | O_RDWR, 0644);
printf("fd1=%d, fd2=%d, fd3=%d\n", fd1, fd2, fd3);
close(fd2); // 关闭 fd2
int fd4 = open("file4.txt", O_CREAT | O_RDWR, 0644);
printf("fd4=%d\n", fd4); // 输出 fd4
sleep(5); // 等待一段时间
int fd5 = open("file5.txt", O_CREAT | O_RDWR, 0644);
printf("fd5=%d\n", fd5); // 输出 fd5
close(fd1);
close(fd3);
close(fd4);
close(fd5);
return 0;
}
3. 代码拆解
文件描述符的初始分配
程序首先打开三个文件,分别返回文件描述符 fd1、fd2、fd3。
由于标准输入(0)、标准输出(1)、标准错误(2)已经被占用,新打开的文件描述符从 3 开始分配。
因此,fd1=3、fd2=4、fd3=5。
int fd1 = open("file1.txt", O_CREAT | O_RDWR, 0644); // fd1=3
int fd2 = open("file2.txt", O_CREAT | O_RDWR, 0644); // fd2=4
int fd3 = open("file3.txt", O_CREAT | O_RDWR, 0644); // fd3=5
printf("fd1=%d, fd2=%d, fd3=%d\n", fd1, fd2, fd3); // 输出:fd1=3, fd2=4, fd3=5
关闭文件描述符并立即重新分配
程序关闭 fd2(即文件描述符 4),释放该文件描述符。
立即打开一个新文件 file4.txt,内核会分配当前可用的最小文件描述符。
由于 4 刚刚被释放,内核会优先分配 4,因此 fd4=4。
close(fd2); // 关闭 fd2(4)
int fd4 = open("file4.txt", O_CREAT | O_RDWR, 0644);
printf("fd4=%d\n", fd4); // 输出fd4
等待一段时间后重新分配
程序调用 sleep(5),等待 5 秒。
打开一个新文件 file5.txt,内核会分配当前可用的最小文件描述符。
由于 0~5 已经被重新分配,内核会分配下一个可用的文件描述符 6,因此fd5=6。
sleep(5); // 等待 5 秒
int fd5 = open("file5.txt", O_CREAT | O_RDWR, 0644);
printf("fd5=%d\n", fd5); // 输出fd5
文件描述符的关闭
程序关闭所有打开的文件描述符,释放资源。
close(fd1);
close(fd3);
close(fd4);
close(fd5);
4. 内核行为解释
最小可用原则:内核总是优先分配当前可用的最小文件描述符。
文件描述符的缓存与回收:内核可能会缓存最近释放的文件描述符,以便快速重用。但在某些情况下(如延迟回收),内核可能会跳过缓存的文件描述符,分配其他可用的文件描述符。
5. 总结
(1)文件描述符的分配遵循最小可用原则。
(2)关闭文件描述符后,内核可能会立即重用或延迟重用该文件描述符。
(3)这种行为体现了内核的资源管理策略,包括文件描述符的缓存、延迟回收和最小可用原则。