I'm developing an iOS app in Swift that captures a video of a rotating view, but I'm facing a memory leak issue. After the video is exported, there's still an excess of 2GB stored in memory, which is not deallocated even after the function completes. This issue persists and crashes the app when attempting to run the function a second time in production.
The issue seems to occur when creating image buffers. Here's the relevant code snippet:
// ViewFrame struct and render method
struct ViewFrame {
private let image: UIImage?
private let snapshot: UIView?
// ... initializers omitted for brevity ...
func render() -> UIImage {
if let existingImage = image {
return existingImage
} else {
return snapshot!.asImage(afterScreenUpdates: true)
}
}
}
// RecordView function within ViewRecordingSession class
private func recordView() {
// ... other code omitted for brevity ...
Timer.scheduledTimer(withTimeInterval: 1 / framesPerSecond, repeats: true) { [weak self] timer in
guard let strongSelf = self else { return }
if !strongSelf.isRecording {
timer.invalidate()
uiView.removeFromSuperview()
} else {
if strongSelf.useSnapshots, let snapshotView = uiView.snapshotView(afterScreenUpdates: false) {
strongSelf.frames.append(ViewFrame(snapshot: snapshotView))
} else {
strongSelf.frames.append(ViewFrame(image: uiView.asImage(afterScreenUpdates: false)))
}
// ... other code omitted for brevity ...
}
}
}
// GenerateAsset function within ViewRecordingSession class
private func generateAsset() {
assetGenerationCancellable?.cancel()
let frameImages = frames.map { $0.render() }
// ... other code omitted for brevity ...
}
Using the Memory Graph Debugger, I've identified that the CG raster data is not being deallocated. The specific function that's contributing to the leak is UIView.asImage(afterScreenUpdates:).
The Memory Graph indicates a strong reference to the views or images captured is preventing deallocation. How can I ensure that these objects are released correctly after they are used?
I think it's good to check out a few parts
1. Check Whether ViewFrame's snapshot is being used or not
ex)
2. Check
timer.invalidate()You use [weak self] in Timer.scheduledTimer's action block. But
timer.invalidate()is not called in your's code3. Check
ViewRecordingSession's framesAfter you append viewFrame in
frames, you may be not remove viewFram inframesI hope it helps your situation. have a nice day~