Skip to main content
 首页 » 操作系统

ios之内存泄漏 : steady increase in memory usage with simple device motion logging

2024年01月01日45mayingbao

考虑将设备运动数据记录到磁盘上的 CSV 文件中的这个简单的 Swift 代码。

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 { $0.description }) + "\n" 
        let encoded = line.dataUsingEncoding(NSUTF8StringEncoding)! 
 
        self.handle!.writeData(encoded) 
    }) 
} 

我已经坚持了好几天了。似乎有内存泄漏,因为内存 消耗量稳步增加,直到操作系统因超出资源而暂停应用程序。

此应用能够长时间不间断地运行至关重要。一些注意事项:

  • 我已经尝试使用 NSOutputStream 和 CSV 写入库 (CHCSVParser),但问题仍然存在
  • 异步执行日志记录代码(将 startDeviceMotionUpdatesToQueue 包装在 dispatch_async 中)不会解决问题
  • 在后台 NSOperationQueue 中执行传感器数据处理 确实 解决了这个问题(仅当 maxConcurrentOperationCount >= 2 时)。然而,这会导致文件写入中的并发问题:输出文件中出现乱码,其中的行彼此交织在一起。
  • 仅在记录加速度计数据时似乎不会出现此问题,但在记录多个传感器(例如加速度计 + 陀螺仪)时似乎会出现。是否存在触发此问题的文件写入吞吐量阈值?
  • 内存峰值似乎以大约 10 秒的间隔间隔开(上图中的步骤)。也许这表明了什么? (可能是内存检测基础设施的产物,或者可能是垃圾收集)

有什么指点吗?我尝试过使用 Instruments,但我不具备有效使用它的技能。内存使用量激增似乎是由 __NSOperationInternal 引起的。这是一个示例 Instruments trace .

谢谢。

请您参考如下方法:

首先,看我的这个回答:

https://stackoverflow.com/a/28566113/341994

您不应该在调试器中查看内存图;只相信 Instruments 告诉你的。在 Swift 中,调试构建和发布构建的内存管理方式截然不同。

其次,如果仍有问题,请尝试将处理程序的内部包裹在 autoreleasepool 闭包中。但是,我不认为这会有所作为(因为这不是循环),而且我不认为这是必要的,因为我怀疑使用 Instruments 会揭示一开始就没有任何问题.但是,autoreleasepool 调用将确保自动释放的对象没有机会累积。