You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

排查SwiftUI macOS应用中Apple核心框架相关内存泄漏

SwiftUI macOS应用内存持续增长排查困境

问题概述

  • 开发的SwiftUI macOS应用存在内存持续增长问题,运行数小时后会彻底卡顿。
  • 已尝试使用Xcode Memory Graph和Instruments工具排查内存泄漏,但示例中的问题都较为明显,自身问题难以定位。
  • 运行Instruments后发现泄漏对象并不固定:
    泄漏对象不固定
  • Xcode Memory Graph显示泄漏源头是CoreFoundation下的NSSet,无法定位到自身代码,作为新手陷入困境。

补充调查进展

初步怀疑

怀疑问题与AVPlayer组件相关,后续调查进一步验证了这一方向。

关键发现

启动AVPlayer播放后内存会无限制增长,标注后的内存分析图如下:
AVPlayer播放时内存无限制增长

AVPlayer相关代码实现

struct VideoPlayerView: NSViewRepresentable {
@Environment(GlobalTimelineModel.self) var globalTimelineModel

var playerView: AVPlayerView
var player: AVPlayer
@Binding var currentPlayerTime: CMTime
@Binding var isPlaying: Bool

@Binding var loopStart: Double
@Binding var loopEnd: Double
@Binding var shouldLoop: Bool

@Binding var isScrubbing: Bool

@State var shouldResumePlayback: Bool = false /// 拖动进度条暂停播放时设为true

func makeCoordinator() -> Coordinator {
    Coordinator(self)
}


func makeNSView(context: Context) -> AVPlayerView {
    playerView.player = player
    playerView.controlsStyle = .none
    playerView.player?.replaceCurrentItem(with: globalTimelineModel.videoAVPlayerItem)
    playerView.player?.isMuted = true
    
    context.coordinator.onTimeUpdate = { time in
        currentPlayerTime = time
    }
    
    return playerView
}

func updateNSView(_ nsView: AVPlayerView, context: Context) {
    if nsView.player != player{
        nsView.player = player
    }
    
    if isPlaying{
        player.playImmediately(atRate: 1.0)
        
        // 播放到结尾时从头开始
        if let playerCurrentTime = nsView.player?.currentTime().seconds, let playerDuration = nsView.player?.currentItem?.duration.seconds{
            
            if playerCurrentTime >= playerDuration{
                player.seek(to: .zero, toleranceBefore: .zero, toleranceAfter: .zero)
            }
        }
        
      
    }
    else{
        if player.rate != 0{
            player.pause()
        }
    }

}

func updatePlaybackPosition(player: AVPlayer){
    player.seek(to: currentPlayerTime, toleranceBefore: .zero, toleranceAfter: .zero)
}

func isWithinThreshold(value1: Double, value2: Double, threshold: Double) -> Bool {
    return abs(value1 - value2) <= threshold
}




class Coordinator {
        private var timeObserverToken: Any?
        private weak var player: AVPlayer? // 使用弱引用持有player
        var onTimeUpdate: ((CMTime) -> Void)?
        
        init(_ parent: VideoPlayerView) {
            print("Coordinator初始化")
            self.player = parent.player // 存储player的弱引用
            addPeriodicTimeObserver()
        }
        
        private func addPeriodicTimeObserver() {
            guard let player = player else { return }
            let interval = CMTime(value: 1, timescale: 24)
            timeObserverToken = player.addPeriodicTimeObserver(forInterval: interval,
                                                      queue: .main) { [weak self] time in
                guard let self = self else { return }
                self.onTimeUpdate?(time)
            }
        }
        
        private func removePeriodicTimeObserver() {
            guard let timeObserverToken = timeObserverToken,
                  let player = player else { return }
            player.removeTimeObserver(timeObserverToken)
            self.timeObserverToken = nil
        }
        
        deinit {
            print("Coordinator销毁")
            removePeriodicTimeObserver()
        }
    }
}

内存分析细节图

内存分析细节


内容的提问来源于stack exchange,提问作者user1542125

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 21:29:51