太多的AVPlayers导致由于内存问题而终止 [英] Too many AVPlayers causes Terminated due to memory issue

查看:96
本文介绍了太多的AVPlayers导致由于内存问题而终止的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个内有 AVPlayer 的vc.通过该vc,我可以在其中具有其他播放器的情况下推入另一个vc,并且我也可以在其中具有播放器的情况下继续推更多的vc.大约 14th 个VC被推入应用程序后,由于内存问题终止了 Terminate .

I have a vc that has an AVPlayer inside of it. From that vc I can push on a different vc with another player inside of it and I can keep pushing on more vcs with a player inside them also. After about the 14th vc getting pushed on the app crashes with Terminated due to memory issue.

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

When I look at the memory graph (9th icon in left pane) it's at about 70mb so there isn't an obscene jump in memory. All of my video files are saved to and retrieved from disk and whenever I pop a vc I have a print statement inside Deinit that always runs so there isn't anything else causing the memory issue. This led me to believe the other SO answers that said that there is a limit to 16 AVPlayers at the same time. The reason I think all of these players are causing this memory crash is because once I comment out the player initialization code I can push on 30 vcs with no crashes whatsoever.

我正要从中的父级vc中完全删除播放器,playerItem,它的观察者和播放器层,然后在 viewWillAppear中再次初始化所有子项,然后弹出子项./viewDidAppear ,但随后我遇到了此博客那说

I was about to completely remove the player, playerItem, its observers, and player layer from the parent vc in viewWillDisappear/viewDidDisappear and then once the child is popped reinitialize everything again in viewWillAppear/viewDidAppear but then I came across this blog that says

共享视频渲染管道"数量的平台限制设备上的应用之间.事实证明,将AVPlayer设置为nil不会释放播放管道,实际上它是playerItem与在其中创建管道的播放器的关联第一名

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

和该答案,内容为

这不是对AVPlayer实例数量的限制,或者AVPlayerItem.而是AVPlayerItem与AVPlayer,可创建渲染管道"

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"

问题是,当在新的vc上推送/弹出(它将有一个播放器)时,我是否需要完全删除/读取与播放器相关的所有内容,或者将 AVPlayerItem 设置为 nil 然后重新初始化它可以解决问题?

The question is when pushing/popping on a new vc (it will have a player inside of it) do I need to completely remove/readd everything associated with the player or will setting the AVPlayerItem to nil then reinitializing it again resolve the issue?

如果渲染管道引起了问题,则似乎限制不是在播放器上,而是在playerItems上.

If the render pipelines are causing the problem it would seem that the limit isn't on the players but on the playerItems.

代码:

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内分别插入一个 AVPlayer 每个都没有任何崩溃.

I just tested it and setting this to nil and reinitializing it is what allowed me to push on 30 vcs each with an AVPlayer inside of each one without any crashes whatsoever.

player?.replaceCurrentItem(with: nil)

所以问题不是 AVPlayers 的总数,就像这家伙说的 AVPlayerItem与AVPlayer的关联会创建一个渲染管道,而同时太多它们是导致问题的原因.

So the issue isn't the total amount of AVPlayers, it's like this guy said, the association of AVPlayerItem with an AVPlayer which creates a "render pipeline and too many of them at the same time is what causes the problem.

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

    // !isMovingToParent only runs when popping back, *** I haven't tested it with presentation/dismissal ***
    if !isMovingToParent {

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

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

这篇关于太多的AVPlayers导致由于内存问题而终止的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆