我的 AVPlayer 的内存在哪里?如何取回它?

2024-02-08

我正在同时播放大量视频AVPlayer。为了减少加载时间,我将相应的视图存储在NSCache.

这种方法效果很好,直到达到一定数量的视频,视频就会停止播放,甚至不再出现。

没有错误、日志或内存警告。特别是,我正在听UIApplicationDidReceiveMemoryWarningNotification清除缓存,但这从未收到。

如果我删除缓存,所有视频都会播放,但性能会下降。

这让我怀疑AVPlayer正在使用来自不同进程的内存(哪个进程?)。当内存达到一定限度时,新玩家就会停止工作。

它是否正确?

如果是这样,是否有办法在达到此神奇限制时收到通知,以采取适当的措施(例如清除缓存)以确保其他媒体的播放?


好消息和坏消息 - 好消息是您可能可以解决问题,坏消息是它需要工作并且有些复杂。

根本问题

你没有提前收到通知的原因是,iOS 直到几乎为时已晚才发现你的应用程序已超出其内存预算,然后立即杀死它。该问题与 iOS(和 OS X)管理文件系统缓存的方式有关。通常,当文件打开时,当您读取数据时,文件数据会传输到缓冲区中Unified Buffer Cache(您可以通过谷歌搜索该术语以获取更多信息)-从现在起我将其称为 UBC。

因此,假设您有 10 个打开的文件,并且您已读完每个文件,但尚未关闭这些文件。嗯,所有这些数据都保存在 UBC 中。现在,如果关闭文件,缓冲区将全部被释放。从技术上讲,操作系统也可以清除这些缓冲区 - 只是当它意识到内存紧张时,它会选择首先清除应用程序(并且可能有充分的理由这样做)。因此,想象一下您的应用程序正在显示视频,并且加载视频的方式是通过文件系统,可用缓冲区的数量开始下降。在某些时候,iOS 会注意到这一点,追踪谁最属于(您的应用程序),然后尽快杀死您的应用程序。

我自己在我支持的开源项目中遇到了这个问题,相片卷轴网络 https://github.com/dhoerl/PhotoScrollerNetwork。用户开始抱怨他们的项目像您一样被系统终止,而没有任何通知。我尝试监控 UBC,但没有成功(OS X 上有 API 可以这样做,但 iOS 上没有)。最后我找到了一个使用启发式的解决方案 - 监视所有内存使用情况,包括 UBC,并且不要超过总可用 iOS 内存池的 50%。

那么(你可能会问)——苹果批准的解决这个问题的方法是什么?嗯,没有。我怎么知道呢?因为我在 WWDC 2012 上与一个实验室的 Core iOS 总监进行了长达半小时的讨论(其他人不知道我在说什么)。最后,在我解释了上述启发之后,他直接告诉我,这个解决方案可能是他能想到的最好的解决方案。如果没有 API 直接监控 UBC,您只能估算其使用情况并进行相应调整。

但你说,我正在使用 NSCache - 为什么系统不考虑AVPlayer记忆在那里?原因无疑是UBC——AVPlayer实例本身可能只消耗几千K的内存——它是iOS不考虑的视频的打开文件。

可能的解决方案

1)如果你可以将视频直接加载到 NSData 对象中,并将其保留在 NSCache 中,那么你很可能完全避免上面提到的 UBC 问题。 [我对 AV 系统了解不够,不知道你是否可以做到这一点。] 在这种情况下,系统should能够在需要时清除内存。

2) 继续使用原来的代码,但添加内存管理。也就是说,当您创建 AVPlayer 实例时,您需要考虑视频的大小(以字节为单位),并保留所有这些内存的运行记录。当您接近设备可用内存总量的 50% 时,开始清除旧的 AVPlayer。

Code

为了完整起见,我提供了相关代码相片卷轴网络 https://github.com/dhoerl/PhotoScrollerNetwork以下。如果您想了解更多详细信息,可以仔细阅读该项目 - 然而它非常复杂,因此需要花费一些时间(它对大量图像进行动态 JPEG 解码,并在解码过程中将图块写入文件系统)。

// Data Structure
typedef struct {
    size_t freeMemory;
    size_t usedMemory;
    size_t totlMemory;
    size_t resident_size;
    size_t virtual_size;
} freeMemory;

在您的应用程序的早期:

// ubc_threshold_ratio defaults to 0.5f
// Take a big chunk of either free memory or all memory
freeMemory fm       = [self freeMemory:@"Initialize"];
float freeThresh    = (float)fm.freeMemory*ubc_threshold_ratio;
float totalThresh   = (float)fm.totlMemory*ubc_threshold_ratio;
size_t ubc_threshold = lrintf(MAX(freeThresh, totalThresh));
size_t ubc_usage = 0;

// Method on some class to monitor the memory pool
- (freeMemory)freeMemory:(NSString *)msg
{
    // http://stackoverflow.com/questions/5012886
    mach_port_t host_port;
    mach_msg_type_number_t host_size;
    vm_size_t pagesize;
    freeMemory fm = { 0, 0, 0, 0, 0 };

    host_port = mach_host_self();
    host_size = sizeof(vm_statistics_data_t) / sizeof(integer_t);
    host_page_size(host_port, &pagesize);        

    vm_statistics_data_t vm_stat;

    if (host_statistics(host_port, HOST_VM_INFO, (host_info_t)&vm_stat, &host_size) != KERN_SUCCESS) {
        LOG(@"Failed to fetch vm statistics");
    } else {
        /* Stats in bytes */ 
        natural_t mem_used = (vm_stat.active_count +
                              vm_stat.inactive_count +
                              vm_stat.wire_count) * pagesize;
        natural_t mem_free = vm_stat.free_count * pagesize;
        natural_t mem_total = mem_used + mem_free;

        fm.freeMemory = (size_t)mem_free;
        fm.usedMemory = (size_t)mem_used;
        fm.totlMemory = (size_t)mem_total;

        struct task_basic_info info;
        if(dump_memory_usage(&info)) {
            fm.resident_size = (size_t)info.resident_size;
            fm.virtual_size = (size_t)info.virtual_size;
        }

#if MEMORY_DEBUGGING == 1
        LOG(@"%@:   "
            "total: %u "
            "used: %u "
            "FREE: %u "
            "  [resident=%u virtual=%u]", 
            msg, 
            (unsigned int)mem_total, 
            (unsigned int)mem_used, 
            (unsigned int)mem_free, 
            (unsigned int)fm.resident_size, 
            (unsigned int)fm.virtual_size
        );
#endif
    }
    return fm;
}

当您打开视频时,将尺寸添加到ubc_usage,当你关闭一个时减少它。当您想打开新视频时,请测试 ubc_usageubc_threadhold,它超出了您必须首先关闭某些内容的值。

PS:您可以尝试在其他时间调用该 freeMemory 方法,然后看看,但就我而言,当文件打开时它几乎没有变化 - 系统似乎将整个 UBC 视为“免费”,因为它could如果需要的话清除它(我猜)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

我的 AVPlayer 的内存在哪里?如何取回它? 的相关文章

  • iOS:提高图像绘制速度

    我有一系列想要制作动画的图像 UIImageView支持一些基本的动画 但不足以满足我的需求 我的第一个方法是使用UIImageView并设置image当图像属性 这太慢了 速度慢的原因是图像的绘制 这让我感到惊讶 我以为瓶颈会加载图像 我
  • iphone NSDate 转换问题

    在我的 facebook 图表 Api 中 我正在获取这些数据 来自杰森 updated time 2011 05 17T14 52 16 0000 我正在使用此代码将其转换为有效的日期格式 NSDateFormatter df NSDat
  • 个人帐户开发者之间的 Apple 开发/分发证书

    我一直在到处寻找有关处理证书的正确答案 想象一下以下帐户 Joe拥有个人 Apple 帐户 但他根本不会编码 他只是发布了该应用程序并将其称为自己的 Bob还有一个个人 Apple 帐户 Bob 是一位编码专家 Joe 付费让他开发他的第一
  • 我的游戏中应该有多少个视图控制器?

    我开始使用 spritekit 构建我的第一个游戏 现在我只有一个视图控制器来呈现开始屏幕场景 override func viewDidLoad super viewDidLoad let scene StartScreenScene C
  • WhatsApp 显示警告“此项目无法共享。请选择其他项目。”对于 iOS 应用程序。

    我正在开发一个 iOS 应用程序 在该应用程序中 我有社交共享功能 并且社交共享功能使用深度链接来共享 URL 该网址共享对于所有应用程序都运行良好 除了WhatsApp 它会显示一个警报弹出窗口 此项目无法共享 请选择其他项目 以下是我的
  • 为什么我的视图仍然以横向呈现?

    我的视图是由导航控制器控制的 因此我将导航控制器支持的方向设置为明确的纵向和纵向UpSideDown 这可以工作 但是如果调用视图时前一个视图处于横向状态 它将以横向方式呈现并保持横向状态 直到设备旋转 如何防止这种情况发生 这是我的代码
  • 苹果企业程序分发问题[关闭]

    Closed 这个问题是无关 help closed questions 目前不接受答案 这个问题涉及到Apple iOS 开发者企业计划 http developer apple com programs ios enterprise 我
  • Swift C 回调 - Swift 类指针的 takeUnretainedValue 或 takeRetainedValue

    我有一些UIView or UITableViewCell 里面我有 C 回调 例如 CCallback bridge self observer data gt Void in let mySelf Unmanaged
  • 分发内部业务 IOS 应用程序

    我遇到了 IOS 应用程序分发的一个令人困惑的部分 因此 我需要简单细分一下我的限制 即仅将我的应用程序分发给我的员工 同事或任何被视为 内部 的人 这是表明我不希望该应用程序出现在应用程序商店中的另一种方式 我的情况是我为几家公司开发 他
  • 苹果推送通知在生产中不起作用

    我们完全陷入困境 请帮忙 我和我的团队制作了一个 iPhone 应用程序 这是我们第一次在 iOS 上尝试 一切都很好 直到我们提交应用程序并在应用程序商店上可用为止 推送通知服务无法正常工作 我在网上搜索并尝试根据人们的建议仔细检查我们的
  • 检索 iPhone 中的 Outlook 联系人

    我想通过应用程序导入所有 Outlook 联系人 有什么办法可以做到这一点吗 请告诉我 您可以通过实施 Microsoft Exchange 服务器协议来实现此目的 微软MSDN http msdn microsoft com en us
  • 无法在 iOS 企业应用程序中连接到 example.com

    我面临着一个严重的问题 我正在尝试使企业应用程序上线 通过使用 BetaBuilder 我按照以下步骤操作 myApp ipa manifest plist index html 清单 plist
  • 相当于 Interface Builder 中 UIButton 的动态类型“自动调整字体”设置?

    UILabel 有一个Dynamic Type Automatically Adjusts FontInterface Builder 属性检查器中的复选框 Interface Builder 中是否有等效项用于自动调整 UIButton
  • 如何使用MKMapView完成加载委托,可能的“完成显示”委托?

    当用户在选择注释后点击 保存 时 我尝试保存地图视图的缩略图 当用户尚未放大该注释时会出现问题 因此尚未加载关闭缩放级别 这就是用户点击保存后我正在做的事情 将布尔值 saving 设置为 true 居中并放大注释 无动画 当调用mapVi
  • 如何在 UICollectionView 的节标题中动态添加标签和按钮?

    请帮助我如何水平添加标签和水平添加类似的按钮 但每个按钮应像另一个部分一样在每个标签的下方对齐 这应该在 UICollectionView 的标题中动态发生 因为标签和按钮的数量根据我的数据 我想制作一种 Excel 类型的布局 并在标题中
  • 防止UIScrollView的UIPanGestureRecognizer遮挡UIScreenEdgePanGestureRecognizer

    我有一个UIScrollView它填满了我应用程序的一页上的屏幕 但我希望允许用户从屏幕边缘平移以显示其后面的视图 问题是 UIScrollView 窃取了我的触摸UIScreenEdgePanGestureRecognizer在屏幕边缘
  • 使用 NSURLSessionDataTask 显示文件下载进度

    我想显示特定文件的文件下载进度 收到了多少字节 它与 NSURLSessionDownloadTask 配合得很好 我的问题是我想用 NSURLSessionDataTask 实现同样的效果 以下是将文件接收到 NSData 并写入文档文件
  • iOS - NSNotificationCenter 多个UIKeyboard通知

    我有两个视图控制器 我们称它们为 A 和 B 1 在 A 中 我显示一个包含文本字段的 popOver 2 B中有一个UITextView用于简单的文本编辑 我必须管理 A 和 B 中的键盘才能滚动键盘隐藏的内容 我知道如何重新定位内容 我
  • 在 Flutter 中显示 iOS 的 PDF 内联文件

    我正在 flutter 中专门为 iOS 开发一个应用程序 现阶段 我需要向其中添加 PDF 文件 问题是 flutter 没有原生的方式来显示 PDF 文件 据我研究 由此tread https github com flutter fl
  • 不使用控件时,视频元素在 Chrome 中消失

    So I think这是一个浏览器错误 它出现在一个更复杂的设计 网站中 但我已经进行了很好的尝试 简化了我的代码和设计等 并发现了以下内容 嵌入时

随机推荐