Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

播时长较长的视频发生memory issue #27

Closed
justinjcode opened this issue Jun 27, 2022 · 5 comments
Closed

播时长较长的视频发生memory issue #27

justinjcode opened this issue Jun 27, 2022 · 5 comments

Comments

@justinjcode
Copy link

image
image
播1小时以上的视频,内存很快就涨起来了
另外player销毁后,下载任务没有销毁,内存还是持续上涨。

@eroscai
Copy link
Owner

eroscai commented Jun 28, 2022

好的,当我有空闲时间时会跟进一下,不过你可以提供一些更详细一点的信息:

  1. 播放1小时视频时的内存问题是常规使用场景下就出现还是需要一些特殊条件?比如在工程DEMO里面设置长视频时是否同样出现?
  2. player销毁问题也是同上,是否可以在工程DEMO里复现?

如果工程DEMO里能复现,能提供一个外网能访问的长视频链接最好了。

@justinjcode
Copy link
Author

你好作者,我先描述下场景:
我是在自己开发的app里,播放一个时长较长,总大小约300MB左右的在线视频,大约有以下几种操作都会有问题
1.开始播放后内存占用会慢慢上涨;
2.如果此时拖动进度条触发多次seekToTime,那内存就会很明显上涨;
3.关闭当前player,新建player播放其它视频,也会导致内存明显上涨;
上述3种操作,配合大尺寸的视频,内存问题就会很明显,作者有空可以试试。
另外,我今天自己跟进了一天,发现并修复了以下几个点:

  1. 在SZAVPlayerAssetLoader里,系统会多次回调resourceLoader(_ resourceLoader: ,shouldWaitForLoadingOfRequestedResource loadingRequest:) -> Bool,这个回调会触发多个data request操作,每个data request在请求到媒体数据后都会占用不小的内存。问题出在了resourceLoader(_ : didCancel loadingRequest: )这个回调的处理,系统需要取消之前的一些请求,这里作者调用了dataLoader.cancel(),但实际上并没有停掉之前的请求(具体第2点详细说明)。这里取消掉所有的任务也不大合理,应该要根据具体的loadingRequest去找到对应的operation,取消它们。
  2. SZAVPlayerDataLoaderOperation是对应系统的每一次loadingRequest,它可能会触发多个SZAVPlayerRequestOperation来请求具体数据。这两者都是继承Operation,作者在取消这两种任务是,都是调用了cancel,但实际上它们并没有被移除,它们的deinit方法也没有打印到控制台。我后面查了一下资料,应该是要把isFinished置为true,把isExecuting置为false,才会使任务真正被移除。也就是在cancel方法里调用markAsFinished()。经过我的自测,加上这个处理后,被取消的operation都会释放了,内存也处于平缓的波动区间。
  3. 除了上面说的内存问题,还有一个缓存文件的问题,在SZAVPlayerLocalFileInfo里,新增文件名并没有跟uniqueID绑定,所以本地缓存也没有生效。
    static func newFileName(uniqueID: String) -> String {
    let timeInterval = Int64(Date().timeIntervalSince1970 * 1000)
    return "(timeInterval)"
    }
    我试了一下,需要用uniqueID跟startOffset唯一确定文件名,才能有效的使用本地缓存

@eroscai
Copy link
Owner

eroscai commented Jun 30, 2022

好的,感谢详细的回复,问题1和2我空的时候看一下。

问题3的话应该是你遗漏了一些追踪吧。
虽然newFileName方法里没有用到uniqueID,但这里其实只需要一个唯一性的文件名创建出来即可,用到它的save方法会把其他信息一并存入到数据库中,参考这里:

public func save(uniqueID: String, mediaData: Data, startOffset: Int64) {

实际用到的时候会使用uniqueID从数据库获取相关信息,参考这里:
let localFileInfos = SZAVPlayerDatabase.shared.localFileInfos(uniqueID: uniqueID)

然后根据offset和其他信息从本地文件获取需要的数据,参考这里:
tmpOperation = addLocalFileRequest(startOffset: &startOffset, endOffset: endOffset, fileInfo: fileInfo)

你可以再次确认一下这个逻辑是不是正常。

@eroscai
Copy link
Owner

eroscai commented Jul 2, 2022

问题2已经修复,cancel的时候没有调用markAsFinished方法确实是个问题,之前在其他场景中有修复过,但是忘记同步到这个库里了。
至于问题1里的dataLoader.cancel()方法调用cancelAllOperations方法来取消现有的全部operation的逻辑,我大概回忆了一下这样写的原因:

  • resourceLoader(_ : didCancel loadingRequest: )方法调用的时机我记得一般有两种情况
    • 一种是用户触发了seekToTime方法,也就是产生了新的Range请求
    • 一种是在不同iOS系统版本下dataRequest的触发逻辑会有不同表现,简单来说data请求开始时会有未预期的cancel回调,接着发来一个新的data请求
  • 不管是针对上述两种情况还是其他cancel调用的情况,应该都可以理解为把现有请求取消掉,为即将触发的新的请求腾出网络资源应该是还算合理的做法
    • 如果不做清理操作可能出现的一种情况是seekToTime等方法调用时会等待比较长的时间(之前其他的data请求占着网络资源)

你可以使用最新的master分支代码来测试你的问题是否正常,如果OK的话到时候我发布一个小版本上去

@justinjcode
Copy link
Author

justinjcode commented Jul 2, 2022 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants