从文件句柄读取数据会泄漏Linux上的内存

时间:2017-08-07 00:42:38

标签: swift linux swift3 memory-leaks

从文件读取数据时遇到内存泄漏。此代码创建泄漏:

func read() throws {
    let url = URL(fileURLWithPath: "content.pdf")
    let fileHandle = try FileHandle(forReadingFrom: url)
    while true {
        let chunk = fileHandle.readData(ofLength: 256)
        guard !chunk.isEmpty else {
            break
        }
    }
    print("read")
}

do {
   for _ in 0 ..< 10000 {
        try read()
    }
}
catch {
    print("Error: \(error)")
}

* FYI:要运行此代码,您必须拥有&#34; content.pdf&#34;文件在你的工作目录中。

如果我使用Swift 3.1.1(或3.1)在Linux上运行它,它会循环多次迭代,消耗越来越多的内存,直到进程被终止。

在Mac上也会发生这种情况,因为数据被放入自动释放池中,我可以通过将每次迭代包装在自动释放池中来解决内存问题,但这在Linux上不存在,所以我不知道我怎么能释放那段记忆。有没有人有想法?

2 个答案:

答案 0 :(得分:3)

我发现了标准库中的问题。实际上已经开放bug report了。基本上问题是readData(ofLength :)方法返回一个Data对象,该对象在解除分配后不会自行清理。

目前,我正在使用此解决方法:

extension FileHandle { 
    public func safelyReadData(ofLength length: Int) -> Data {
        #if os(Linux)
            var leakingData = self.readData(ofLength: length)
            var data: Data = Data() 
            if leakingData.count > 0 { 
                leakingData.withUnsafeMutableBytes({ (bytes: UnsafeMutablePointer<UInt8>) -> Void in
                    data = Data(bytesNoCopy: bytes, count: leakingData.count, deallocator: .free)
                })
            } 
            return data
        #else
            return self.readData(ofLength: length)
        #endif
    }
}

我之前使用的任何地方readData(ofLength:)我现在正在使用safelyReadData(ofLength:)方法。在除Linux以外的所有平台上,它只是调用原始版本,因为这些实现很好。在Linux上,我正在创建一个数据副本,在释放时实际释放基础数据。

答案 1 :(得分:0)

而不是如何解决丢失的自动释放池,更好的问题是如何防止泄漏。也许创建(而不是解除分配)10,000个FileHandles是个问题。试试这个。

func read() throws {
    let url = URL(fileURLWithPath: "content.pdf")
    let fileHandle = try FileHandle(forReadingFrom: url)
    while true {
        let chunk = fileHandle.readData(ofLength: 256)
        guard !chunk.isEmpty else {
            break
        }
    }
    fileHandle.closeFile()
    print("read")
}

这可能不是问题,但它仍然是良好的代码卫生。在崩溃之前制作了多少个循环?