太多的 AVPlayer 导致 Terminated due to memory issue

Too many AVPlayers causes Terminated due to memory issue

我有一个 vc,里面有一个 AVPlayer。从那个 vc 我可以推动一个不同的 vc 与另一个球员在里面,我可以继续推动更多 vcs 与他们里面的球员。在大约 14th vc 被推送后,应用程序崩溃 Terminated due to memory issue

当我查看内存图(左窗格中的第 9 个图标)时,它大约为 70mb,因此内存中没有令人讨厌的跳跃。我所有的视频文件都保存到磁盘并从磁盘检索,每当我弹出 vc 我在 Deinit 中有一个打印语句 总是运行 所以没有'没有其他原因导致内存问题。这让我相信了其他 SO 答案,这些答案说同时存在 16 AVPlayers 的限制。我认为所有这些播放器导致此内存崩溃的原因是,一旦我注释掉播放器初始化代码,我就可以继续 30 vcs 而不会出现任何崩溃。

我正要在 viewWillDisappear/viewDidDisappear 中从父 vc 中完全删除播放器、playerItem、它的观察者和播放器层,然后在 [=16] 中弹出子项后再次重新初始化所有内容=] 但后来我发现 this blog

platform limitation on the number of video “render pipelines” shared between apps on the device. It turns out that setting the AVPlayer to nil does not free up a playback pipeline and that it is actually the association of a playerItem with a player that creates the pipeline in the first place

和这个 answer

It is not a limit on the number of instances of AVPlayer, or AVPlayerItem. Rather,it is the association of AVPlayerItem with an AVPlayer which creates a "render pipeline"

问题是当 pushing/popping 在新的 vc 上(里面会有一个播放器)我是否需要完全 remove/readd 与播放器相关的所有内容或将设置将 AVPlayerItem 更改为 nil 然后重新初始化它是否解决了问题?

如果 渲染管道 导致了问题,那么似乎限制不在播放器上,而是在播放器项目上。

代码:

override func viewDidLoad() {
    super.viewDidLoad()

    configurePlayer(with: self.videoUrl)
}

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    // only runs when popping back
    if !isMovingToParent {

        // I can either
        let asset = AVAsset(url: selfvideoUrl)
        self.playerItem = AVPlayerItem(asset: asset)
        self.player?.replaceCurrentItem(with: playerItem!)

        // or just reinitialize everything
        configurePlayer(with: self.videoUrl)
    }
}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    
    // would these 2 lines be enough suffice to prevent the issue?
    self.player?.replaceCurrentItem(with: nil)
    self.playerItem = nil

    // or do I also need to nil out everything?
    self.player = nil
    self.avPlayerView.removeFromSuperView()
    self.playerStatusObserver = nil
    self.playerRateObserver = nil
    self.playerTimeControlStatusObserver = nil
}


func configurePlayer(with videoUrl: URL) {

    let asset = AVAsset(url: videoUrl)
    self.playerItem = AVPlayerItem(asset: asset)

    self.player = AVPlayer()
    self.playerLayer = AVPlayerLayer(player: player)
    self.playerLayer?.videoGravity = AVLayerVideoGravity.resizeAspect
    self.player?.automaticallyWaitsToMinimizeStalling = false
    self.playerItem.preferredForwardBufferDuration = TimeInterval(1.0)

    view.addSubview(avPlayerView) // this is just a view with a CALayer for the playerLayer
    self.playerLayer?.frame = avPlayerView.bounds
    self.avPlayerView.layer.addSublayer(playerLayer!)
    self.avPlayerView.playerLayer = playerLayer

    self.player?.replaceCurrentItem(with: playerItem!)

    // add endTimeNotification

    setNSKeyValueObservers()
}

func setNSKeyValueObservers() {

    self.playerStatusObserver = player?.observe(\.currentItem?.status, options: [.new, .old]) {
        [weak self] (player, change) in ... }

    self.playerRateObserver = player?.observe(\.rate, options:  [.new, .old], changeHandler: { 
        [weak self](player, change) in ... }

    self.playerTimeControlStatusObserver = player?.observe(\.timeControlStatus, options: [.new, .old]) {
        [weak self](player, change) in ... }
}

我刚刚对其进行了测试,并将其设置为 nil 并重新初始化它,这让我能够在没有任何崩溃的情况下推送 30 个 vc,每个 vc 中都有一个 AVPlayer

player?.replaceCurrentItem(with: nil)

所以问题不在于 AVPlayers 的总量,而是 this guy saidthe association of AVPlayerItem with an AVPlayer which creates a "render pipeline 并且同时出现太多才是导致问题的原因。

override func viewDidLoad() {
    super.viewDidLoad()

    configurePlayer(with: self.videoUrl)
}


override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    if let playerItem = playerItem {
        self.player?.replaceCurrentItem(with: playerItem)
    }
}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    
    self.player?.replaceCurrentItem(with: nil)
}