UE4 Low Level Memory Tracker使用
发布日期:2021-06-29 12:05:31 浏览次数:2 分类:技术文章

本文共 3518 字,大约阅读时间需要 11 分钟。

简介

LLM(Low Level Memory Tracker) 是从 4.18 开始引入的新的内存统计工具,比 memreport 统计数据更加详细精确,但又不会像 MallocProfiler 那样有很大的本身开销

相关代码实现在 

 

Engine\Source\Runtime\Core\Public\HAL\LowLevelMemTracker.h Engine\Source\Runtime\Core\Private\HAL\LowLevelMemTracker.cpp 

 

功能开关

编译开关

在 Development 和 Debug 下,LLM 相关的代码是默认编译的,在 Test 模式下,需要在 YourGame.Target.cs 文件中增加宏定义 

 

ALLOW_LOW_LEVEL_MEM_TRACKER_IN_TEST=1

 

 才会编译相关代码,Shipping 模式下不会编译

运行开关

  • 在编译时打开 LLM 后,要想在运行时使用 LLM 的功能,还要加上启动命令行 

 

-LLM //运行时打开 LLM 统计-LLMCSV //将内存统计信息输出到 CSV 文件中,CSV 文件保存在 Saved\Profiling\LLM 目录下

 

如果想在运行时默认生效,可以在 Target.cs 文件中增加宏定义 LLM_AUTO_ENABLE=1

资源统计分类

命令行 -LLMTAGSETS,用来指示资源统计分类是按类别来分,还是按具体资源来分,不过要使用这个功能需要在编译时在代码中打开LLM_ALLOW_ASSETS_TAGS宏(这个宏目前不能在 Target.cs 文件添加)

 

-LLMTAGSETS=Assets:按资源分类统计-LLMTAGSETS=AssetClasses:按资源类别分类统计

 

运行时开关 LLM 的处理见 FLowLevelMemTracker::ProcessCommandLine 函数

显示统计命令行

运行时,可以通过以下命令行来显示当前的统计信息

  • stat LLM: 显示 Default Tracker 分组的简要内存统计信息

  • stat LLMFULL: 显示 Default Tracker 分组的所有内存统计信息

  • stat LLMOveread: 显示 LLM 本身使用的内存信息

  • stat LLMPlatform: 显示 Platform Tracker 分组的内存统计信息

  • LLM.LLMWriteInterval: 修改 LLM 的内存信息写入 csv 文件的频率,默认 5 秒写一行

移动端开启LLM

Android 命令行

在已经装好版本的手机上,如果想要启动 LLM,可以通过 push UE4CommandLine.txt 到手机上动态改变游戏启动参数

新建一个 UE4CommandLine.txt,内容如下

 

../../../YourProject/YourProject.uproject -LLM -LLMCSV

 

新建一个 PushCommandLine.bat 并执行,内容如下

 

%ANDROID_HOME%\platform-tools\adb.exe shell mkdir -p /sdcard/UE4Game/YourProject%ANDROID_HOME%\platform-tools\adb.exe push UE4CommandLine.txt /sdcard/UE4Game/YourProject/UE4CommandLine.txt

 

IOS 命令行

IOS 需要将 ue4commandline.txt 通过文件共享复制到 Documents 目录下,注意这里的文件名是全小写

CSV 文件输出

指定 -LLMCSV 命令行后,会得到两个 csv 文件,

  • 一个是 LLM_ 前缀,LLM 主要关注 FMalloc 内存的消费者,主要就是引擎内各个部分的内存开销

另一个是 LLMPlatform_ 前缀,LLMPlatform 只关注系统内存的消费者,主要有几大类: ProgramSize, FMalloc, LLMOverhead。

注意,当同时指定 -LLMTAGSETS 命令行后,CSV 文件会错乱,因为写 CSV 文件时预留了第一行标题栏内容的缓冲区,当打开 LLMTAGSETS 之后,因为每个资源或资源类很多,会导致标题栏内容溢出,覆盖了后面的数据区域,所以这里需要自己按需求修改一下。

LLM标记

引擎(包括游戏代码)的每次内存分配都会被指定一个标记值,用于标识其所属的类别。也就是说,所有内存仅被跟踪一次,没有任何内存错过或被计算两次。所有类别的总计会累计到游戏所用的总内存。

添加自定义标签

除了以上的分类标签外,还可以添加自定义的标签,主要有两种方式

静态添加

修改 LowLevelMemTrakcer.h 文件在 LLM_ENUM_GENERIC_TAGS按照同样格式添加

动态地注册新标签

按同样格式添加一个新标签定义另外一种是通过调用RegisterPlatformTag/RegisterProjectTag,主要参数如下:

 

Tag: 标签枚举,不要和其它地方重复了Name签名,显示在 CSV 文件的标题栏中StatName: 与这个标签相关的 Stat 统计,在游戏中通过 stat 命令来显示,使用 DECLARE_LLM_MEMORY_STAT宏进行定义,可以为空(NAME_None)SummaryStatName: 汇总 Stat 统计,可以将多个 LLM STAT 汇总在一起,可以为空(NAME_None)ParentTag: 父级标签枚举值,父级标签对应的内存值是所有子级标签的和,级数最多两级

 

 

 

DECLARE_LLM_MEMORY_STAT(TEXT("Test"), STAT_TestLLM, STATGROUP_LLMFULL);enum class EMyLLMTag{  TestTag = ELLMTag::ProjectTagStart + 20,}void Init(){  LLM(FLowLevelMemTracker::Get().RegisterProjectTag((int32)EMyLLMTag::TestTag, TEXT("Test"), GET_STATFNAME(STAT_TestLLM), NAME_None));}void TestFunc(){    LLM_SCOPE(EMyLLMTag::TestTag);}

 

添加及应用标记流程

要添加新的标记,需要执行以下步骤:

  1. 将值添加到 LowLevelMemTracker.h 中的 ELLMTag 列举类型。

  2. 将相应的元素添加到 LowLevelMemTracker.cpp 中的 ELLMTagNames数组中。

  3. 使用 LLM_SCOPE宏将标记范围添加到代码中。

如果范围是特定于平台的,则以相同的方式添加到特定于平台的LLM文件中的列举类型,例如,PlayStation 4的 PS4LLM.cpp和PS4LLM.h

技术实现细节

LLM的作用原理是维护由指针索引的所有分配的映射。该映射当前包含每个分配的大小及其指定的标记。游戏一次可有多达400万个实时分配,因此内存开销必须尽可能少。当前实现中每个分配使用21个字节:

 

 

分配

 

大小

 

指针

 

8个字节

 

指针散列键

 

4个字节

 

大小

 

4个字节

 

标记

 

1个字节

 

散列图索引

 

4个字节

 

  1. 使用 OnLowLevelAlloc函数跟踪分配时,标记堆栈顶部的标记将成为当前标记,存储在分配映射中,以该指针作为其关键帧。

  2. 为了避免争用,在单独的 FLLMThreadState类实例中跟踪每个标记的帧增量。在帧结束时,这些增量将相加并发布到统计信息系统和 .CSV 文件。

标记使用范围宏进行应用。以下是两个主要的宏:

 

LLM_SCOPE(Tag)LLM_PLATFORM_SCOPE(Tag)

 

这两个宏分别设置了默认跟踪器和平台跟踪器的当前范围。这些范围有平台相关版本,例如 

 

LLM_SCOPE_PS4(Tag)

 

,它使用特定于平台的标记列举类型。使用统计信息的范围宏(例如 

 

LLM_SCOPED_TAG_WITH_STAT

 

)目前被视为已弃用,不应被使用。

LLM内部使用的所有内存均由平台提供的 

 

LLMAlloc和LLMFree

 

函数管理。LLM不以任何其他方式进行分配,因此它不会跟踪自己的内存使用情况(并导致无穷递归),这一点非常重要。

 

 

转载地址:https://blog.csdn.net/zzZZ20150101/article/details/117063506 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:UE4 PhyX物理引擎应用介绍
下一篇:UE4 Sequence使用

发表评论

最新留言

路过按个爪印,很不错,赞一个!
[***.219.124.196]2024年04月26日 00时38分05秒