前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android平台上的Native内存分析

Android平台上的Native内存分析

作者头像
逍遥剑客
发布2019-02-20 15:28:55
4.2K0
发布2019-02-20 15:28:55
举报

背景

UE4游戏在Android上的进程内存占用(PSS)很让人困惑, 没有一个清晰直观的方式可以统计到每一部分的内存占用. 所以在做内存分析的过程中顺手做了一个统计工具, 可以从系统底层统计UE4在Android的所有内存分配(包括Graphics部分).

在这里插入图片描述
在这里插入图片描述

UE4的内存统计

UE4本身提供了3种内存分析方式:

下面分别做一下说明

memreport

游戏中console command输入”memreport-full”可以保存内存报告在Saved/Profiling/MemReports目录下, 就是一个文本文件, 长这样:

在这里插入图片描述
在这里插入图片描述

里面有各种类型的内存统计数据, 如Texture, RTT, VB/IB, Particle, Component等, 每一种都有比较详细的信息. 缺点是引擎只会从某个角度做统计, 对于一些统计代码没有覆盖到的内存是没有相关信息的, 而且各个统计类型之间是有重叠, 无法把各个子项加起来就能还原出内存的总体占用分布.

MemoryProfiler2

引擎代码中打开USE_MALLOC_PROFILER宏, 编译后使用”mprof start/stop/snapshot”命令来dump内存日志, 再使用MemoryProfiler2.exe打开查看:

在这里插入图片描述
在这里插入图片描述

MemoryProfiler2的统计是基于UE4的内存分配器, 通过记录每次内存操作的调用堆栈, 然后进行累加统计, 使用GUI工具按照树形结构显示出来, 能够非常直观地进行分析. 缺点是会影响内存分配的效率, 而且记录的信息量太大, 中低端Android手机很难保存成功, 抓取到后工具的分析效率也比较慢. 如果一些内存没有通过UE4的内存分配器进行分配的话, 那是统计不到的, 比如一些第三方库或者组件.

LLM

LLM是4.18才加入的功能, 使用-LLM命令行参数启动才生效, 当时只有PC和主机平台可以用, 游戏中使用”stat LLM/LLMFULL”打开实时查看:

在这里插入图片描述
在这里插入图片描述

这种统计方式是基于scope的方式, 类似CPU性能分析的原理, 执行某段代码前记录一下, 执行后再统计对比一下, 这样可以做到没有遗漏, 而且也不会影响游戏的执行性能. 缺点是只是按模块或者分类的统计, 没有更细节的信息指导优化.

Android进程内存

使用dumpsys meminfo命令可以查看Android进程的内存占用信息:

代码语言:javascript
复制
adb shell dumpsys meminfo <package_name|pid> [-d]

一般输出的信息像这样:

在这里插入图片描述
在这里插入图片描述

基中Gfv dev, EGL mtrack, GL mtrack是新版本Android才加入的, 之前版本都被统计在Native Heap中. 对比memreport就会发现, Unknown部分基本上与UE4自身统计到的内存一致, 那是因为UE4底层调用了mmap/munmap来进行内存分配, 所以没有被系统统计到Native Heap中:

代码语言:javascript
复制
FMalloc* FAndroidPlatformMemory::BaseAllocator()
{
	const FPlatformMemoryConstants& MemoryConstants = FPlatformMemory::GetConstants();
	// 1 << FMath::CeilLogTwo(MemoryConstants.TotalPhysical) should really be FMath::RoundUpToPowerOfTwo,
	// but that overflows to 0 when MemoryConstants.TotalPhysical is close to 4GB, since CeilLogTwo returns 32
	// this then causes the MemoryLimit to be 0 and crashing the app
	uint64 MemoryLimit = FMath::Min<uint64>( uint64(1) << FMath::CeilLogTwo(MemoryConstants.TotalPhysical), 0x100000000);

#if PLATFORM_ANDROID_ARM64
	// todo: track down why FMallocBinned is failing on ARM64
	return new FMallocAnsi();
#else
	// [RCL] 2017-03-06 FIXME: perhaps BinnedPageSize should be used here, but leaving this change to the Android platform owner.
	return new FMallocBinned(MemoryConstants.PageSize, MemoryLimit);
#endif
}

void* FAndroidPlatformMemory::BinnedAllocFromOS(SIZE_T Size)
{
	void* Ptr = mmap(nullptr, Size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
	LLM(FLowLevelMemTracker::Get().OnLowLevelAlloc(ELLMTracker::Platform, Ptr, Size));
	return Ptr;
}

如果把FMallocBinned替换成FMallocAnsi, 那么所有的内存都会被统计进Native Heap, 这时就可以使用Android的Malloc Debug进行内存分析了:

在这里插入图片描述
在这里插入图片描述

DDMSMemoryAnalyzer

代码语言:javascript
复制
注: 这个方法只在MiPad(Android4.4)上测试过, 最新版本Android的DDMS已经没有这个功能了.
  • 首先保证/system/lib/libc_malloc_debug_leak.so存在, 如果没有, 需要自行提取相应版本并拷贝过去
  • 然后setprop libc.debug.malloc 1, 开启系统级的Malloc Debug(也可以指定进程)
  • C:\Users[yourname].android\ddms.cfg, 加一行””native=true”
  • 启动ddms.bat, “Snapshot Current Native Heap Usage”, 可以抓取一个带有调用堆栈地址的txt文件
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

有了堆栈地址, 我们可以通过arm-linux-androideabi-addr2line.exe把地址翻译成函数名. 由于txt中保存的是内存地址, 而addr2line需要的是so的相对地址, 所以我们需要获取libUE.so的内存地址, 做个减法, 才能使用addr2line进行翻译. 使用以下命令可以找到libUE4.so的内存地址:

代码语言:javascript
复制
adb shell pmap -x [PID]

比如下图, libUE4.so的内存地址是70226000:

在这里插入图片描述
在这里插入图片描述

有了so的相对地址, 就可以使用addr2line进行翻译了:

代码语言:javascript
复制
arm-linux-androideabi-addr2line.exe -C -s -f -e libUE4.so [ADDRESS]

但是txt中记录的是每次调用的堆栈, 次数非常多, 每一次的分配大小都比较小, 不具备实际优化的参考价值, 所以把所有的堆栈地址合并进行内存的累加统计, 以树形结构自上而下查看, 内存占用就变得非常直观了, 这就是DDMSMemoryAnalyzer的基本思想:

在这里插入图片描述
在这里插入图片描述

同样的方法, 也适用于Unity引擎:

在这里插入图片描述
在这里插入图片描述
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018年09月28日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 背景
  • UE4的内存统计
    • memreport
      • MemoryProfiler2
        • LLM
        • Android进程内存
        • DDMSMemoryAnalyzer
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档