太多的 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 said、the 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)
}
我有一个 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 said、the 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)
}