内存泄漏:通过简单的设备运动日志记录内存使用量稳步增加
Memory leak: steady increase in memory usage with simple device motion logging
考虑这个简单的 Swift 代码,它将设备运动数据记录到磁盘上的 CSV 文件中。
let motionManager = CMMotionManager()
var handle: NSFileHandle? = nil
override func viewDidLoad() {
super.viewDidLoad()
let documents = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as NSString
let file = documents.stringByAppendingPathComponent("/data.csv")
NSFileManager.defaultManager().createFileAtPath(file, contents: nil, attributes: nil)
handle = NSFileHandle(forUpdatingAtPath: file)
motionManager.startDeviceMotionUpdatesToQueue(NSOperationQueue.currentQueue(), withHandler: {(data, error) in
let data_points = [data.timestamp, data.attitude.roll, data.attitude.pitch, data.attitude.yaw, data.userAcceleration.x,
data.userAcceleration.y, data.userAcceleration.z, data.rotationRate.x, data.rotationRate.y, data.rotationRate.z]
let line = ",".join(data_points.map { [=10=].description }) + "\n"
let encoded = line.dataUsingEncoding(NSUTF8StringEncoding)!
self.handle!.writeData(encoded)
})
}
我已经坚持了好几天了。似乎有内存泄漏,因为内存
消耗量稳步增加,直到 OS 因超出资源而暂停应用程序。
此应用能够 运行 长时间不间断运行至关重要。一些注意事项:
- 我试过使用 NSOutputStream 和 CSV 写入库 (CHCSVParser),但问题仍然存在
- 异步执行日志记录代码(将
startDeviceMotionUpdatesToQueue
包装在 dispatch_async
中)不会消除问题
- 在后台执行传感器数据处理
NSOperationQueue
确实 解决了问题(仅当 maxConcurrentOperationCount
>= 2 时)。但是,这会导致文件写入的并发问题:输出文件出现乱码,行之间相互缠绕。
- 仅在记录加速度计数据时似乎不会出现此问题,但在记录多个传感器(例如加速度计 + 陀螺仪)时似乎会出现。是否存在触发此问题的文件写入吞吐量阈值?
- 内存峰值似乎以大约 10 秒的间隔间隔开(上图中的步骤)。也许这表明了什么? (可能是内存检测基础设施的产物,或者可能是垃圾收集)
有什么指点吗?我尝试过使用 Instruments,但我不具备有效使用它的技能。看来内存使用量的爆炸式增长是由 __NSOperationInternal
引起的。这是一个示例 Instruments trace.
谢谢。
先看我的这个回答:
您不应该在调试器中查看内存图;只相信 Instruments 告诉你的。在 Swift.
中,调试构建和发布构建的内存管理方式非常不同
其次,如果仍有问题,请尝试将处理程序的内部包裹在 autoreleasepool
闭包中。但是,我不认为这会有所作为(因为这不是循环),而且我不认为这是必要的,因为我怀疑使用 Instruments 会揭示一开始就没有任何问题.但是,autoreleasepool
调用将确保自动释放的对象没有机会累积。
考虑这个简单的 Swift 代码,它将设备运动数据记录到磁盘上的 CSV 文件中。
let motionManager = CMMotionManager()
var handle: NSFileHandle? = nil
override func viewDidLoad() {
super.viewDidLoad()
let documents = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as NSString
let file = documents.stringByAppendingPathComponent("/data.csv")
NSFileManager.defaultManager().createFileAtPath(file, contents: nil, attributes: nil)
handle = NSFileHandle(forUpdatingAtPath: file)
motionManager.startDeviceMotionUpdatesToQueue(NSOperationQueue.currentQueue(), withHandler: {(data, error) in
let data_points = [data.timestamp, data.attitude.roll, data.attitude.pitch, data.attitude.yaw, data.userAcceleration.x,
data.userAcceleration.y, data.userAcceleration.z, data.rotationRate.x, data.rotationRate.y, data.rotationRate.z]
let line = ",".join(data_points.map { [=10=].description }) + "\n"
let encoded = line.dataUsingEncoding(NSUTF8StringEncoding)!
self.handle!.writeData(encoded)
})
}
我已经坚持了好几天了。似乎有内存泄漏,因为内存 消耗量稳步增加,直到 OS 因超出资源而暂停应用程序。
此应用能够 运行 长时间不间断运行至关重要。一些注意事项:
- 我试过使用 NSOutputStream 和 CSV 写入库 (CHCSVParser),但问题仍然存在
- 异步执行日志记录代码(将
startDeviceMotionUpdatesToQueue
包装在dispatch_async
中)不会消除问题 - 在后台执行传感器数据处理
NSOperationQueue
确实 解决了问题(仅当maxConcurrentOperationCount
>= 2 时)。但是,这会导致文件写入的并发问题:输出文件出现乱码,行之间相互缠绕。 - 仅在记录加速度计数据时似乎不会出现此问题,但在记录多个传感器(例如加速度计 + 陀螺仪)时似乎会出现。是否存在触发此问题的文件写入吞吐量阈值?
- 内存峰值似乎以大约 10 秒的间隔间隔开(上图中的步骤)。也许这表明了什么? (可能是内存检测基础设施的产物,或者可能是垃圾收集)
有什么指点吗?我尝试过使用 Instruments,但我不具备有效使用它的技能。看来内存使用量的爆炸式增长是由 __NSOperationInternal
引起的。这是一个示例 Instruments trace.
谢谢。
先看我的这个回答:
您不应该在调试器中查看内存图;只相信 Instruments 告诉你的。在 Swift.
中,调试构建和发布构建的内存管理方式非常不同其次,如果仍有问题,请尝试将处理程序的内部包裹在 autoreleasepool
闭包中。但是,我不认为这会有所作为(因为这不是循环),而且我不认为这是必要的,因为我怀疑使用 Instruments 会揭示一开始就没有任何问题.但是,autoreleasepool
调用将确保自动释放的对象没有机会累积。