【经验】使用Profiler工具分析内存占用情况

本文深入分析了Unity3D官方例子AngryBots的内存使用情况,通过Profiler工具详细解读了内存占用的主要部分,并提供了针对性的优化策略,包括改善Texture2D、AudioClip和Mesh等资源的管理,以及关注ManagedHeap和SerializedFile的使用,旨在提高游戏性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

       Unity3D为我们提供了一个强大的性能分析工具Profiler。今天我们就使用Profiler来详细分析一下官方例子AngryBots的内存使用信息数据。

       首先打开Profiler选择Memory选项,在游戏运行的某一帧查看Detailed选项数据(Simple模式的数据很直观,可以知道内存大体被哪部分占用了,网上也有很多相关介绍,我就不再啰嗦了),如下图所示:


选中后,unity会自动获取这一帧的内存占用数据项,主要分为:Other、Assets、BuiltinResources、Scene Memory、NotSaved这五大部分,下面我们就来一一分析。

  • Other


记录数据项很多,篇幅时间有限,我们就专挑占用大小排行榜靠前的几项来详细分析吧。

  • System.ExecutableAndDlls:系统可执行程序和DLL,是只读的内存,用来执行所有的脚本和DLL引用。不同平台和不同硬件得到的值会不一样,可以通过修改Player Setting的Stripping Level来调节大小。

Ricky:我试着修改了一下Stripping Level似乎没什么改变,感觉虽占用内存大但不会影响游戏运行。我们暂时忽略它吧(- -)!

  • GfxClientDevice:GFX(图形加速\图形加速器\显卡 (GraphicsForce Express))客户端设备。

Ricky:虽占用较大内存,但这也是必备项,没办法优化。继续忽略吧(- -)!!

  • ManagedHeap.UsedSize:托管堆使用大小。

Ricky:重点监控对象,不要让它超过20MB,否则可能会有性能问题!

  • ShaderLab:Unity自带的着色器语言工具相关资源。

Ricky:这个东西大家都比较熟悉了,忽略它吧。

  • SerializedFile:序列化文件,把显示中的Prefab、Atlas和metadata等资源加载进内存。

Ricky:重点监控对象,这里就是你要监控的哪些预设在序列化中在内存中占用大小,根据需求进行优化。

  • PersistentManager.Remapper:持久化数据重映射管理相关

Ricky:与持久化数据相关,比如AssetBundle之类的。注意监控相关的文件。

  • ManagedHeap.ReservedUnusedSize:托管堆预留不使用内存大小,只由Mono使用。

Ricky:无法优化。

  • Assets


  • Texture2D: 2D贴图及纹理。


Ricky:重点优化对象,有以下几点可以优化:

  1. 许多贴图采用的Format格式是ARGB 32 bit所以保真度很高但占用的内存也很大。在不失真的前提下,适当压缩贴图,使用ARGB 16 bit就会减少一倍,如果继续Android采用RGBA Compressed ETC2 8 bits(iOS采用RGBA Compressed PVRTC 4 bits),又可以再减少一倍。把不需要透贴但有alpha通道的贴图,全都转换格式Android:RGB Compressed ETC 4 bits,iOS:RGB Compressed PVRTC 4 bits。
  2. 当加载一个新的Prefab或贴图,不及时回收,它就会永驻在内存中,就算切换场景也不会销毁。应该确定物体不再使用或长时间不使用就先把物体制空(null),然后调用Resources.UnloadUnusedAssets(),才能真正释放内存。
  3. 有大量空白的图集贴图,可以用TexturePacker等工具进行优化或考虑合并到其他图集中。

  • AudioManager:音频管理器

Ricky:随着音频文件的增多而增大。

  • AudioClip:音效及声音文件

Ricky:重点优化对象,播放时长较长的音乐文件需要进行压缩成.mp3或.ogg格式,时长较短的音效文件可以使用.wav 或.aiff格式。

  • Cubemap:立方图纹理

Ricky:这个一般在天空盒中比较常见,我也不知道如何优化这个。。。

  • Mesh:模型网格

Ricky:主要检查是否有重复的资源,还有尽量减少点面数。

  • Scene Memory

  • Mesh:场景中使用的网格模型

Ricky:注意网格模型的点面数,能合并的mesh尽量合并。

  • Builtin Resources

Ricky:这些都是Unity的一些内部资源,对于项目内存没有什么分析价值,所以我就暂时不对其进行分析了。

  • Profiler内存重点关注优化项目

1)ManagedHeap.UsedSize: 移动游戏建议不要超过20MB.

2)SerializedFile: 通过异步加载(LoadFromCache、WWW等)的时候留下的序列化文件,可监视是否被卸载.

3)WebStream: 通过异步WWW下载的资源文件在内存中的解压版本,比SerializedFile大几倍或几十倍,不过我们现在项目中展示没有。

4)Texture2D: 重点检查是否有重复资源和超大Memory是否需要压缩等.

5)AnimationClip: 重点检查是否有重复资源.

6)Mesh: 重点检查是否有重复资源.

  • 项目中可能遇到的问题

1.Device.Present:

1)GPU的presentdevice确实非常耗时,一般出现在使用了非常复杂的shader.

2)GPU运行的非常快,而由于Vsync的原因,使得它需要等待较长的时间.

3)同样是Vsync的原因,但其他线程非常耗时,所以导致该等待时间很长,比如:过量AssetBundle加载时容易出现该问题.

4)Shader.CreateGPUProgram:Shader在runtime阶段(非预加载)会出现卡顿(华为K3V2芯片).

5)StackTraceUtility.PostprocessStacktrace()和StackTraceUtility.ExtractStackTrace(): 一般是由Debug.Log或类似API造成,游戏发布后需将Debug API进行屏蔽。

2.Overhead:

1)一般情况为Vsync所致.

2)通常出现在Android设备上.

3.GC.Collect:

原因:

1)代码分配内存过量(恶性的)

2)一定时间间隔由系统调用(良性的).

占用时间:

1)与现有Garbage size相关

2)与剩余内存使用颗粒相关(比如场景物件过多,利用率低的情况下,GC释放后需要做内存重排)

4.GarbageCollectAssetsProfile:

1)引擎在执行UnloadUnusedAssets操作(该操作是比较耗时的,建议在切场景的时候进行)。

2)尽可能地避免使用Unity内建GUI,避免GUI.Repaint过渡GCAllow.

3)if(other.tag == a.tag)改为other.CompareTag(a.tag).因为other.tag为产生180B的GC Allow.

4)少用foreach,因为每次foreach为产生一个enumerator(约16B的内存分配),尽量改为for.

5)Lambda表达式,使用不当会产生内存泄漏.

5.尽量少用LINQ:

1)部分功能无法在某些平台使用.

2)会分配大量GC Allow.

6.控制StartCoroutine的次数:

1)开启一个Coroutine(协程),至少分配37B的内存.

2)Coroutine类的实例 -> 21B.

3)Enumerator -> 16B.

7.使用StringBuilder替代字符串直接连接.

8.缓存组件:

1)每次GetComponent均会分配一定的GC Allow.

2)每次Object.name都会分配39B的堆内存.

 

Ricky Yang个人原创,版权所有,转载注明,谢谢。http://blog.csdn.net/yangyy753

<think>我们正在讨论如何使用Profiler工具分析C++进程的内存占用。根据之前的对话,用户已经提到了GooglePerftools(gperftools)的使用,并且引用[3]中也提到了类似的方法。现在用户再次询问如何用Profiler分析C++应用程序的内存占用,因此我们将重点放在gperftools的使用上,同时也可以补充其他方法。主要步骤:1.安装gperftools2.运行程序并生成堆分析文件3.使用pprof分析堆文件并生成报告此外,我们还可以提到一些其他工具(如Valgrind的massif)作为备选方案,但以gperftools为主。我们按照用户之前的系统指令要求,包括使用$...$和$$...$$格式,以及生成相关问题。</think> 以下是使用 **Profiler 工具分析 C++ 应用程序内存占用**的完整教程,以 Google Perftools 为例(适用 Linux/macOS): --- ### 一、安装内存分析工具 #### 1. 安装 Google Perftools ```bash # 下载并编译安装 wget https://github.com/gperftools/gperftools/releases/download/gperftools-2.10/gperftools-2.10.tar.gz tar -xvf gperftools-2.10.tar.gz cd gperftools-2.10 ./configure make -j8 && sudo make install ``` #### 2. 验证安装 ```bash pprof --version # 应显示版本号如 2.10 ``` --- ### 二、内存分析实战步骤 #### 1. 编译程序时链接 TCMalloc ```bash g++ -o myapp main.cpp -ltcmalloc # 强制使用TCMalloc内存分配器 ``` #### 2. 运行时生成内存快照 ```bash export HEAPPROFILE=/tmp/myapp_heap # 设置堆分析文件输出路径 ./myapp arg1 arg2 # 正常运行程序 ``` **效果**:每增长 1GB 内存自动生成一个快照文件,如 `/tmp/myapp_heap.0001.heap` --- ### 三、分析内存热点 #### 1. 生成文本报告(快速定位) ```bash pprof --text ./myapp /tmp/myapp_heap.0001.heap > report.txt ``` **报告解读**: ``` Total: 2.3 GB 1.8 GB 78.2% 78.2% Cache::loadImageData() # 热点函数 0.3 GB 13.0% 91.2% std::vector<double>::resize() 0.2 GB 8.7% 99.9% TextureManager::init() ``` - **关键指标**: 第一列:函数自身内存 (GB) 第四列:累计内存占比(定位瓶颈) #### 2. 生成可视化 PDF(调用链分析) ```bash pprof --pdf ./myapp /tmp/myapp_heap.0001.heap > callgraph.pdf ``` **图示重点**: 箭头粗细表示内存流向,红色区块为高内存消耗函数[^3] --- ### 四、Windows 平台方案(VS Profiler) 1. 打开 **Diagnostic Tools**: - [调试] → [窗口] → [显示诊断工具] 2. 内存快照比对: ```markdown 1. 启动程序前点击 [Memory Usage] → [Take Snapshot] 2. 执行目标操作后再次快照 3. 对比两次快照的差值(显示内存增长来源) ``` 3. 查看分配树: - 按模块/函数统计内存占用 - 红色↑标记可疑内存泄漏点(持续增长对象) --- ### 五、优化案例 #### 问题代码(高频临时分配): ```cpp void loadItems() { for (auto& item : items) { std::vector<char> buffer = readFile(item); // 每次循环重新分配 } } ``` #### 优化方案(内存复用): ```cpp void loadItems() { std::vector<char> buffer; // 单次分配 for (auto& item : items) { buffer.clear(); // 清空数据不释放内存 readFile(item, buffer); // 引用传递避免复制 } } ``` **效果**:内存分配次数减少 $90\%$,吞吐量提升 $3\times$[^1] --- ### 六、进阶技巧 1. **实时监控**: ```cpp #include <gperftools/malloc_extension.h> void logMemory() { size_t heap_size; MallocExtension::instance()->GetNumericProperty("generic.current_allocated_bytes", &heap_size); std::cout << "Current heap: " << heap_size/(1024*1024) << " MB"; } ``` 2. **多线程分析**: ```bash export HEAP_PROFILE_ALLOCATION_INTERVAL=100000000 # 每100MB采样一次 export TCMALLOC_SAMPLE_PARAMETER=524288 # 降低采样开销 ``` > 💡 **虚函数开销注意**: > 每个含虚函数的类实例在 64 位系统增加 $8$ 字节虚表指针[^2],高频小对象慎用多态 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ricky_yyy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值