【问题标题】:What happens to Darwin allocated getline buffers?达尔文分配的 getline 缓冲区会发生什么?
【发布时间】:2015-12-17 04:03:23
【问题描述】:

假设我用这样的方式快速调用getline

import Darwin

let byLine = { (file : UnsafeMutablePointer<FILE>) in
    anyGenerator({ () -> String? in
        var input = UnsafeMutablePointer<Int8>()
        var lim = 0
        return getline(&input, &lim, file) > 0 ? String.fromCString(input) : nil
    })
}

请注意ssize_t getline(char **lineptr, size_t *n, FILE *stream); 的此特定文档:

如果在调用前 *lineptr 设置为 NULL 并且 *n 设置为 0,那么 getline() 将分配一个缓冲区来存储该行。这个缓冲区 即使 getline() 失败,也应该由用户程序释放。

现在假设我有:

let fd = fopen("a_billion_lines_of_text.txt", "r")
for line in byLine(fd) {
    ...
}    

for 循环逐行读取该文件时,十亿行文本会发生什么变化?

这段代码确实可以逐行读取文件,但是getline分配的每个行缓冲区会发生什么? swift释放它还是内存泄漏?

【问题讨论】:

  • 鉴于您没有释放文档明确说明需要释放的内容,这是内存泄漏。
  • 如何快速释放它?我知道如何在 C 中做到这一点,但不是间接地在 swift 中。

标签: c swift swift2.1 darwin


【解决方案1】:

缓冲区泄漏。调用getline 后需要释放内存。以下是您可以这样做的方法。

let byLine = { (file : UnsafeMutablePointer<FILE>) in
    anyGenerator({ () -> String? in
        var input = UnsafeMutablePointer<Int8>()
        var lim = 0
        let numChars = getline(&input, &lim, file)
        defer {
            free(input)
        }            
        return numChars > 0 ? String.fromCString(input) : nil
    })
}

【讨论】:

  • defer 是否会在关闭范围内执行并在使用之前释放input
  • input 在使用前不会被释放。 defer 块中的代码将在返回之前执行,但在闭包中的所有其他代码执行完毕之后。这意味着免费将在评估 numChars &gt; 0 ? String.fromCString(input) : nil) 之后发生。
  • 那么函数(闭包)是在释放之前将input 的内容复制到不同的缓冲区?在 C 中,在缓冲区上调用 free 然后从函数返回是一个常见错误...
  • 方法String.fromCString(_:)从缓冲区复制数据(见the documentation)。因此,您不会返回缓冲区本身,而是返回 nil 或通过从缓冲区复制字符数据创建的新字符串。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多