macOS 上 Swift 的 FileHandle.read 或数据缓冲区中的内存泄漏

Mic*_*ael 2 macos swift

FileHandle我尝试使用类和函数使用 Swift 读取 macOS 上的文件

@available(macOS 10.15.4, iOS 13.4, watchOS 6.2, tvOS 13.4, *)
public func read(upToCount count: Int) throws -> Data?
Run Code Online (Sandbox Code Playgroud)

原则上这工作得很好。但是,我面临着内存泄漏。返回的数据缓冲区中分配的数据不会被释放。这可能是底层 Swift 包装器中的错误吗?

这是我的测试函数,它逐块读取文件(否则对数据不执行任何操作)。(是的,我知道,该函数很愚蠢,其唯一目的是证明内存泄漏问题。)

func readFullFile(filePath: String) throws {
    let blockSize = 32 * 1024
    guard let file = FileHandle(forReadingAtPath: filePath) else {
        fatalError("Failed to open file")
    }
    while (true) {
        guard let data = try file.read(upToCount: blockSize) else {
            break
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

如果我在循环中调用该函数,并观察程序的内存消耗,我可以看到内存在每个循环步骤中都会增加读取文件的大小,并且永远不会释放。

任何人都可以确认此行为或知道如何解决它吗?

我的环境:

  • macOS 11.3.1 大苏尔
  • 代码12.5

最好的,迈克尔

Ale*_*ica 5

底层 Objective C 实现使用autorelease. 对象通过线程的自动释放池保持活动状态。通常,该池在运行循环的每次迭代中都会被耗尽。

但在您的上下文中,由于您有一个在运行循环的单次迭代中运行多次的紧密循环,因此您正在积累一堆暂时保留的对象。

请放心,当运行循环迭代完成时,它们最终会被重新分配,假设您的应用程序在此之前没有因 EOM 崩溃。

如果对象的构建是一个问题,您可以通过将分配放入自动释放池块中来手动耗尽自动释放池。

for _ in something {
    autoreleasepool {
        // Do your work here
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意:如果您的工作没有分配太多内存,这实际上可能会使性能变差。它会减慢你的循环速度,但不会带来太多内存好处。

文件:ObjectiveC.autoreleasepool(invoking:)

要访问它,您可以,但更常见的是,当您导入、、等import ObjectiveC时,您会以传递方式导入它。FoundationAppKitCocoa