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
相关产品推荐
相关产品推荐

