百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分析 > 正文

内存扩展:UE中利用IOS新的内存特性

liebian365 2024-10-15 13:51 70 浏览 0 评论

内存优化是游戏开发中经常关注的课题,为了避免App过度分配内存触发OOM被系统强杀,通常的优化手段是从使用层面入手,提升内存的利用效率,裁剪不需要的功能、控制加载的资源等等。

但还有一种情况,提升App触发OOM的阈值,让系统允许我们的App分配更多的内存。在新的IOS版本中,苹果为App引入了新的内存特性,可以允许App扩展寻址空间和提高可分配内存。

本篇文章,我将研究如何把这些特性在UE内利用起来,提高游戏在IOS平台的可分配内存总量。

Apple系列的系统平台中,都提供了一种Entitlements机制,和权限授权不同,它可以授予指定App支持访问特权的能力,如访问HomeKit、地图、iCloud等等,根据具体应用的需要选择性授予,避免能力的滥用。

在Apple Developer中注册App ID时,在创建Identidiers时,会让用户选择App要使用的能力。

Forward

允许App分配更多内存

在IOS15.0+、iPadOS 15.0+的系统版本中,Apple为App开放了一种能力,允许App使用更多的内存,提高App内存分配触发OOM的阈值。

支持版本:iOS 15.0+、iPadOS 15.0+ Entitlement Keycom.apple.developer.kernel.increased-memory-limit

?increased-memory-limit[1]

苹果官方的介绍:

将此权利添加到您的应用程序,以通知系统您的应用程序的某些核心功能可能会因超出受支持设备上的默认应用程序内存限制而表现更好。如果您使用此权利,请确保您的应用程序在额外内存不可用时仍能正常运行。

但苹果没说具体的设备上可分配内存数量能提升多少,后面我会用手头的设备在UE中做一些内存分配测试。

扩展虚拟内存地址

从IOS11开始,Apple就强制要求,、所有上架App Store的App都必须支持64位,32位应用不再支持。

64位应用的好处显而易见:指针范围更大,可使用的虚拟内存也更大,也能超越32位的4G内存限制。在目前流行的设备中,应该绝大部分设备都升级到了IOS11+,所以充分利用64位的性能是有必有的。

在IOS14.0+、iPadOS 14.0+的系统版本中,Apple为App开放了一种能力,允许App扩展虚拟内存地址:Extended Virtual Addressing Entitlement[2]

苹果官方的介绍:

如果您的应用有需要更大可寻址空间的特定需求,请使用此权利。例如,内存映射资产以流式传输到 GPU 的游戏可能受益于更大的地址空间。使用 Xcode 项目编辑器中的“扩展虚拟寻址”功能启用此权利。

启用之后,内核将启用jummbo mode[3],该模式为进程提供完整的64位地址空间访问权限。

支持版本:iOS 14.0+、iPadOS 14.0+、tvOS 14.0+ Entitlement Keycom.apple.developer.kernel.extended-virtual-addressing

国外有位大佬做了IOS虚拟内存扩展的分析:Size Matters: An Exploration of Virtual Memory on iOS[4]

参考资料

?Extended Virtual Addressing Entitlement[5]?increased-memory-limit[6]?Size Matters: An Exploration of Virtual Memory on iOS[7]?一键释放iOS 64位App潜力[8]?如何增加 iOS APP 虚拟地址空间及内存上限?XNU 内核源码解读[9]

实现方式

Capabilities启用

首先要在Apple Developer的页面里开启对应的Capabilities

?Certificates, Identifiers & Profiles[10]

添加之后下载新的MobileProvision,可以在UE中导入它。

如果是原生XCode工程,可以在Xcode中添加Entitlements:

以上操作,会在*.xcodeproj*的同级目录创建一个*.entitlements文件,记录着对应的状态:

<?xml version="1.0" encoding="UTF-8"?>  
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">  
<plist version="1.0">  
<dict>  
        <key>com.apple.developer.kernel.extended-virtual-addressing</key>  
        <true/>  
</dict>  
</plist>

注意,App的Mobile Provision一定要启用对应的能力,不然会在签名时失败。

检查MobileProvision

Mobile Provision是IOS开发的设备描述文件,用于记录证书信息、设备UUID列表、Bundle Identifier等等。

当在App ID中开启大内存支持后,使用MobileProvision打包之前,需要对Mobile Provision中支持的Entitlements进行检查,确保其包含我们需要的两个Key:

com.apple.developer.kernel.increased-memory-limit
com.apple.developer.kernel.extended-virtual-addressing

*.mobileprovision*文件是二进制格式,不能直接使用文本方式打开。但可以在mac上使用security来查看:

 security cms -D -i imzlp.mobileprovision

会输出该MobileProvision的具体信息,检查其中是否包含以下两个Key,且值是否位true

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
        <key>Entitlements</key>
        <dict>
                <key>com.apple.developer.kernel.increased-memory-limit</key>
                <true/>
                <key>com.apple.developer.kernel.extended-virtual-addressing</key>
                <true/>
        </dict>
</dict>
</plist>%

UE中的Entitlements

UE中,在打包时会生成entitlements,会保存在Intermediate-IOS-*.entitlements

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>get-task-allow</key>
    <true/>
</dict>
</plist>

它是在UBT中生成的,具体代码为:Programs/UnrealBuildTool/Platform/IOS/IOSExport.cs[11] 其中有一个WriteEntitlements函数,解析MobileProvision文件,检测里面是否有指定的Identifier。

默认情况下引擎里没有提供方便的追加元素的方式,只能修改UBT实现。

在UE中开启大内存支持

前面提到了UE中,UE中默认没有可以方便追加元素的方式,只能修改UBT的代码实现扩展:

WriteEntitlements中加入以下代码:



//++[lipengzha] support memory-limit
Action<string,string> SupportMemoryOpt = (BoolName,IdStr) =>
{
    bool bBoolNameValue = false;
    // read property in DefaultEngine.ini
    PlatformGameConfig.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", BoolName, out bBoolNameValue);
    Console.WriteLine(string.Format("Write {0}({1}) {2} entitlements",BoolName, bBoolNameValue?"true":"false" ,IdStr));


    if (bBoolNameValue)
    {
        Text.AppendLine(string.Format("\t<key>{0}</key>",IdStr));
        Text.AppendLine(string.Format("\t<{0}/>", bBoolNameValue ? "true" : "false"));
    }
};
SupportMemoryOpt("bIncreasedMemoryLimit","com.apple.developer.kernel.increased-memory-limit");  
SupportMemoryOpt("bExtendedVirtualAddressing","com.apple.developer.kernel.extended-virtual-addressing");
//--[lipengzha]

然后在项目的DefaultEngine.ini中的[/Script/IOSRuntimeSettings.IOSRuntimeSettings]添加以下项:

bIncreasedMemoryLimit=True
bExtendedVirtualAddressing=True

就可以通过控制项目中的配置,来决定是否启用内存扩展的能力。

在打包时就会有以下的Lod:

IOSExport.cs中的逻辑依托于UBT执行,所以如果修改了entitlement,也要让代码有变动(只要UBT能启动编译就可以),不然会出现以下错误:

PackagingResults: Error: Entitlements file "MemoryProfiler.entitlements" was modified during the build, which is not supported. You can disable this error by setting 'CODE_SIGN_ALLOW_ENTITLEMENTS_MODIFICATION' to 'YES', however this may cause the built product's code signature or provisioning profile to contain incorrect entitlements. (in target 'MemoryProfiler' from project 'MemoryProfiler')

也可以删除Intermediate/IOS目录后重试:

测试数据

测试基准:iPhone12,IOS 16.1、iPad Pro 3rd,IOS 16.2

测试工程环境:UE4.27.2,空C++工程,不包含任何额外资源。测试方式:

1.默认实现打包,运行游戏、分配内存直到OOM。2.支持Memory-Limit,运行游戏、分配内存直到OOM。

两者工程和代码均一致,仅有Memory-Limit的支持区别。

运行时的内存分配方式:每次分配1M,直到触发系统OOM,统计分配的内存大小。

Original

iPhone12 Original,游戏启动后的内存:

LogMemoryUsageProfiler: Display: Constants: TotalPhysical 2099.20 MB, TotalVirtual 2099.20 MB PageSize 16384 byte, OsAllocationGranularity 16384, Constants 65536 BinnedAllocationGranularity 0, AddressLimit 100000000
LogMemoryUsageProfiler: Display: Stats: Mem Used 217.73 MB, Texture Memory 8.60 MB, Render Target memory 0.07 MB, OS Free 1881.47 MB

OOM前的内存:

LogMemoryUsageProfiler: Display: AllocSystemMemory: 1 M, Alloced 1889 (M)
LogMemoryUsageProfiler: Display: Constants: TotalPhysical 2099.20 MB, TotalVirtual 2099.20 MB PageSize 16384 byte, OsAllocationGranularity 16384, Constants 65536 BinnedAllocationGranularity 0, AddressLimit 100000000
LogMemoryUsageProfiler: Display: Stats: Mem Used 2098.19 MB, Texture Memory 8.60 MB, Render Target memory 0.07 MB, OS Free 1.01 MB

在距离OOM还有410M时,App触发了系统的内存警告:

LogMemory: Platform Memory Stats for IOS
LogMemory: Process Physical Memory: 1688.24 MB used, 1688.24 MB peak
LogMemory: Process Virtual Memory: 400957.09 MB used, 400957.09 MB peak
LogMemory: Physical Memory: 1688.24 MB used,  410.96 MB free, 2099.20 MB total
LogMemory: Virtual Memory: 2099.20 MB used,  0.00 MB free, 2099.20 MB total

Memory-limit

iPhone12 Memory-limit版本,游戏启动后的内存:

LogMemoryUsageProfiler: Display: Constants: TotalPhysical 2867.20 MB, TotalVirtual 2867.20 MB PageSize 16384 byte, OsAllocationGranularity 16384, Constants 65536 BinnedAllocationGranularity 0, AddressLimit 100000000
LogMemoryUsageProfiler: Display: Stats: Mem Used 735.51 MB, Texture Memory 8.60 MB, Render Target memory 0.07 MB, OS Free 2131.69 MB

OOM前的内存:

LogMemoryUsageProfiler: Display: AllocSystemMemory: 1 M, Alloced 2139 (M)
LogMemoryUsageProfiler: Display: Constants: TotalPhysical 2867.20 MB, TotalVirtual 2867.20 MB PageSize 16384 byte, OsAllocationGranularity 16384, Constants 65536 BinnedAllocationGranularity 0, AddressLimit 100000000
LogMemoryUsageProfiler: Display: Stats: Mem Used 2866.86 MB, Texture Memory 8.60 MB, Render Target memory 0.07 MB, OS Free 0.34 MB

在距离OOM线约460M时,App触发了系统的内存警告:

LogMemory: Platform Memory Stats for IOS
LogMemory: Process Physical Memory: 2407.14 MB used, 2407.14 MB peak
LogMemory: Process Virtual Memory: 401157.25 MB used, 401157.25 MB peak
LogMemory: Physical Memory: 2407.14 MB used,  460.06 MB free, 2867.20 MB total
LogMemory: Virtual Memory: 2867.20 MB used,  0.00 MB free, 2867.20 MB total

总结

启用Memory-Limit机制两个版本对比数据:


Original

Memory-Limit

iPhone12

1889

2139

iPadPro 3rd(2021)

4864

7927

在iPhone12上,开启之后增加了250M可分配内存。

而在iPad Pro 3rd(2021)上,则增加了惊人的3063M!

启用该特性,在高端设备上提升最为明显。不需要做额外的内存使用优化,就从系统手中捡了一大块物理内存,岂不美哉。

References

[1] increased-memory-limit: https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_developer_kernel_increased-memory-limit
[2] Extended Virtual Addressing Entitlement:
https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_developer_kernel_extended-virtual-addressing
[3] jummbo mode:
https://github.com/apple-oss-distributions/xnu/blob/xnu-7195.141.2//bsd/kern/kern_exec.c#L2930-L2932
[4] Size Matters: An Exploration of Virtual Memory on iOS:
https://alwaysprocessing.blog/2022/02/20/size-matters
[5] Extended Virtual Addressing Entitlement:
https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_developer_kernel_extended-virtual-addressing
[6] increased-memory-limit:
https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_developer_kernel_increased-memory-limit
[7] Size Matters: An Exploration of Virtual Memory on iOS:
https://alwaysprocessing.blog/2022/02/20/size-matters
[8] 一键释放iOS 64位App潜力:
https://www.toutiao.com/article/7116717500678570507?wid=1674961795942
[9] 如何增加 iOS APP 虚拟地址空间及内存上限?XNU 内核源码解读:
https://redian.news/wxnews/225476
[10] Certificates, Identifiers & Profiles:
https://developer.apple.com/account/resources/identifiers/list
[11] Programs/UnrealBuildTool/Platform/IOS/IOSExport.cs:
https://github.com/EpicGames/UnrealEngine/blob/release/Engine/Source/Programs/UnrealBuildTool/Platform/IOS/IOSExports.cs#L363

相关推荐

“版本末期”了?下周平衡补丁!国服最强5套牌!上分首选

明天,酒馆战棋就将迎来大更新,也聊了很多天战棋相关的内容了,趁此机会,给兄弟们穿插一篇构筑模式的卡组推荐!老规矩,我们先来看10职业胜率。目前10职业胜率排名与一周前基本类似,没有太多的变化。平衡补丁...

VS2017 C++ 程序报错“error C2065:“M_PI”: 未声明的标识符&quot;

首先,程序中头文件的选择,要选择头文件,在文件中是没有对M_PI的定义的。选择:项目——>”XXX属性"——>配置属性——>C/C++——>预处理器——>预处理器定义,...

东营交警实名曝光一批酒驾人员名单 88人受处罚

齐鲁网·闪电新闻5月24日讯酒后驾驶是对自己和他人生命安全极不负责的行为,为守护大家的平安出行路,东营交警一直将酒驾作为重点打击对象。5月23日,东营交警公布最新一批饮酒、醉酒名单。对以下驾驶人醉酒...

Qt界面——搭配QCustomPlot(qt platform)

这是我第一个使用QCustomPlot控件的上位机,通过串口精确的5ms发送一次数据,再将读取的数据绘制到图表中。界面方面,尝试卡片式设计,外加QSS简单的配了个色。QCustomPlot官网:Qt...

大话西游2分享赢取种族坐骑手办!PK趣闻录由你书写

老友相聚,仗剑江湖!《大话西游2》2021全民PK季4月激燃打响,各PK玩法鏖战齐开,零门槛参与热情高涨。PK季期间,不仅各种玩法奖励丰厚,参与PK趣闻录活动,投稿自己在PK季遇到的趣事,还有机会带走...

测试谷歌VS Code AI 编程插件 Gemini Code Assist

用ClaudeSonnet3.7的天气测试编码,让谷歌VSCodeAI编程插件GeminiCodeAssist自动编程。生成的文件在浏览器中的效果如下:(附源代码)VSCode...

顾爷想知道第4.5期 国服便利性到底需优化啥?

前段时间DNF国服推出了名为“阿拉德B计划”的系列改版计划,截至目前我们已经看到了两项实装。不过关于便利性上,国服似乎还有很多路要走。自从顾爷回归DNF以来,几乎每天都在跟我抱怨关于DNF里面各种各样...

掌握Visual Studio项目配置【基础篇】

1.前言VisualStudio是Windows上最常用的C++集成开发环境之一,简称VS。VS功能十分强大,对应的,其配置系统较为复杂。不管是对于初学者还是有一定开发经验的开发者来说,捋清楚VS...

还嫌LED驱动设计套路深?那就来看看这篇文章吧

随着LED在各个领域的不同应用需求,LED驱动电路也在不断进步和发展。本文从LED的特性入手,推导出适合LED的电源驱动类型,再进一步介绍各类LED驱动设计。设计必读:LED四个关键特性特性一:非线...

Visual Studio Community 2022(VS2022)安装图文方法

直接上步骤:1,首先可以下载安装一个VisualStudio安装器,叫做VisualStudioinstaller。这个安装文件很小,很快就安装完成了。2,打开VisualStudioins...

Qt添加MSVC构建套件的方法(qt添加c++11)

前言有些时候,在Windows下因为某些需求需要使用MSVC编译器对程序进行编译,假设我们安装Qt的时候又只是安装了MingW构建套件,那么此时我们该如何给现有的Qt添加一个MSVC构建套件呢?本文以...

Qt为什么站稳c++GUI的top1(qt c)

为什么现在QT越来越成为c++界面编程的第一选择,从事QT编程多年,在这之前做C++界面都是基于MFC。当时为什么会从MFC转到QT?主要原因是MFC开发界面想做得好看一些十分困难,引用第三方基于MF...

qt开发IDE应该选择VS还是qt creator

如果一个公司选择了qt来开发自己的产品,在面临IDE的选择时会出现vs或者qtcreator,选择qt的IDE需要结合产品需求、部署平台、项目定位、程序猿本身和公司战略,因为大的软件产品需要明确IDE...

Qt 5.14.2超详细安装教程,不会来打我

Qt简介Qt(官方发音[kju:t],音同cute)是一个跨平台的C++开库,主要用来开发图形用户界面(GraphicalUserInterface,GUI)程序。Qt是纯C++开...

Cygwin配置与使用(四)——VI字体和颜色的配置

简介:VI的操作模式,基本上VI可以分为三种状态,分别是命令模式(commandmode)、插入模式(Insertmode)和底行模式(lastlinemode),各模式的功能区分如下:1)...

取消回复欢迎 发表评论: