You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift中关闭Pipe后仍无法创建超2560个,报Too many open files错误

问题:Swift中Pipe创建过多导致"Too many open files"错误

在Swift中使用Pipe()时发现,若创建超过约2560个管道,后续无法再创建,调用会失败并抛出Too many open files错误,即便已关闭所有与管道关联的文件。

复现代码

for i in 0...1278 {
    NSLog("Testing: \(i)")
    let stdin_pipe = Pipe()
    let stdin_file = fdopen(stdin_pipe.fileHandleForReading.fileDescriptor, "r")
    var stdout_pipe = Pipe()
    var stdout_file = fdopen(stdout_pipe.fileHandleForWriting.fileDescriptor, "w")
    if (stdout_file == nil) {
        let errorString = String(cString: strerror(errno))
        NSLog("Could not create an output stream. Error: \(errorString)")
    }
    do {
        // I'm really trying to close everything (but it doesn't matter):
        close(stdout_pipe.fileHandleForWriting.fileDescriptor)
        close(stdin_pipe.fileHandleForReading.fileDescriptor)
        try stdout_pipe.fileHandleForWriting.close()
        try stdin_pipe.fileHandleForReading.close()
        try stdout_pipe.fileHandleForReading.close()
        try stdin_pipe.fileHandleForWriting.close()
    }
    catch {
        NSLog("Error in closing pipes in MyExtension: \(error.localizedDescription)")
    }
}

代码在i从0到1277时正常运行,i=1278时失败,通过strerror(errno)获取到的错误为Too many open files,但检查后发现仅打开了约6个文件描述符,询问哪里操作有误。


解决方案

问题根源

你漏了关闭fdopen返回的FILE*指针。fdopen会复制传入的文件描述符,也就是每个fdopen调用会新增一个关联的文件描述符引用。你只关闭了Pipe自带的文件描述符,但没关闭stdin_file和stdout_file对应的文件描述符,导致每次循环都泄漏2个文件描述符,循环1279次后就达到了进程的文件描述符上限(通常是2560左右)。

修复后的代码

for i in 0...1278 {
    NSLog("Testing: \(i)")
    let stdin_pipe = Pipe()
    let stdin_file = fdopen(stdin_pipe.fileHandleForReading.fileDescriptor, "r")
    var stdout_pipe = Pipe()
    var stdout_file = fdopen(stdout_pipe.fileHandleForWriting.fileDescriptor, "w")
    if (stdout_file == nil) {
        let errorString = String(cString: strerror(errno))
        NSLog("Could not create an output stream. Error: \(errorString)")
    }
    do {
        // 先关闭fdopen创建的FILE*
        if let file = stdin_file {
            fclose(file)
        }
        if let file = stdout_file {
            fclose(file)
        }
        // 再关闭Pipe的文件句柄
        close(stdout_pipe.fileHandleForWriting.fileDescriptor)
        close(stdin_pipe.fileHandleForReading.fileDescriptor)
        try stdout_pipe.fileHandleForWriting.close()
        try stdin_pipe.fileHandleForReading.close()
        try stdout_pipe.fileHandleForReading.close()
        try stdin_pipe.fileHandleForWriting.close()
    }
    catch {
        NSLog("Error in closing pipes in MyExtension: \(error.localizedDescription)")
    }
}

关键说明

  • fdopen会对传入的文件描述符做引用计数,调用fclose才会真正释放这个复制出来的描述符;直接用close关闭原描述符,不会影响fdopen创建的FILE*对应的描述符。
  • 进程的文件描述符上限可以通过ulimit -n查看(macOS/Linux环境),默认通常是2560,这就是为什么你在循环到1279次时触发错误(每次泄漏2个,1279×2=2558,接近上限)。

内容的提问来源于stack exchange,提问作者N. Holzschuch

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 11:52:37