Android Studio 4.1的本机内存分析

This is second in a two part series on What’s New in Profilers in Android Studio 4.1. Our previous post focused on What’s New in System Trace.

这是关于Android Studio 4.1中Profilers新增功能的两部分系列文章的第二部分。 我们之前的文章重点介绍 System Trace中的新增功能

We’ve heard from those of you using C++ that debugging native memory can be fairly difficult, particularly in games. With Android Studio 4.1, we’ve implemented the ability to record call stacks of native memory allocations in our Memory Profiler. The native memory recording is built on top of the Perfetto backend, the next generation performance instrumentation and tracing solution for Android.

我们从使用C ++的人那里听说,调试本机内存可能相当困难,尤其是在游戏中。 使用Android Studio 4.1,我们已经实现了在“内存探查器”中记录本机内存分配的调用堆栈的功能。 本机内存记录建立在Perfetto后端之上, Perfetto后端是适用于Android的下一代性能检测和跟踪解决方案。

A common technique when trying to debug memory issues is to understand what is allocating memory and what is freeing memory. The rest of this article will walk you through how to use the Native Memory Profiler to help track down a leak, using the Gpu Emulation Stress Test as an example project.

尝试调试内存问题时的一种常用技术是了解分配内存的内容和释放内存的内容。 本文的其余部分将以Gpu仿真压力测试为例, 指导您如何使用本机内存探查器来帮助跟踪泄漏。

入门 (Getting Started)

To follow along, clone or download the sample from https://github.com/google/gpu-emulation-stress-test.

要继续进行操作,请从https://github.com/google/gpu-emulation-stress-test克隆或下载示例。

When a memory leak is suspected, it’s often a good idea to start at a high level and watch for patterns in the system memory. To do this click the profile button in Android Studio, and enter the memory profiler for more detailed memory tracking information.

当怀疑存在内存泄漏时,通常最好从高级别开始并注意系统内存中的模式。 为此,请在Android Studio中单击配置文件按钮,然后输入内存分析器以获取更多详细的内存跟踪信息。

Image for post
Top level view of memory profiler. Showing gradual increase in native memory with each run of the “Gpu emulation stress test”
内存分析器的顶层视图。 每次“ Gpu仿真压力测试”运行时,本机内存显示逐渐增加

After running the simulation a few times we can see a few interesting patterns.

运行几次模拟后,我们可以看到一些有趣的模式。

  1. The GPU memory increases as one may expect from a GPU emulation app, however it also looks like this memory gets properly cleaned up after the Activity is finished.

    正如人们可能希望从GPU仿真应用程序中看到的那样,GPU内存增加了,但是看起来在活动完成后,该内存也得到了适当的清理。
  2. The Native memory grows each time we enter the GpuEmulationStressTestActivity, however this memory does not seem to reset after each run, which might be indicative of a leak.

    每次我们输入GpuEmulationStressTestActivity时,本机内存都会增长,但是该内存似乎在每次运行后都不会重置,这可能表明存在泄漏。

本机内存表视图 (Native Memory Table View)

Starting with Android Studio 4.1 Canary 6, we can grab a recording of native memory allocations to analyze why memory isn’t being released. To do this with the GPU emulation app, I stopped the running app and started profiling a fresh instance. Starting from a clean state, especially when looking at an unfamiliar codebase, can help narrow our focus. From the memory profiler I captured a native allocation recording throughout the duration of the GPU emulation demo. To do this restart the app by selecting Run-> Profile ‘app’. After the application starts and the profile window opens, click on the memory profiler and select “record native allocation”

从Android Studio 4.1 Canary 6开始,我们可以获取本地内存分配的记录,以分析为什么不释放内存。 为了使用GPU仿真应用程序执行此操作,我停止了正在运行的应用程序,并开始对新实例进行性能分析。 从干净的状态开始,尤其是在查看不熟悉的代码库时,可以帮助缩小我们的关注范围。 从内存分析器中,我捕获了整个GPU仿真演示期间的本机分配记录。 为此,通过选择运行->配置文件“应用程序”来重启应用程序。 应用程序启动并打开配置文件窗口后,单击内存分析器并选择“记录本机分配”

Image for post
First look at a native memory capture when it is loaded in Android Studio.
首先查看在Android Studio中加载时的本机内存捕获。

The table view is useful for games/applications that use libraries implementing their own allocators highlighting malloc calls that are made outside of new.

表格视图对于使用库实现自己的分配器的游戏/应用程序很有用,该库突出显示了在new之外进行的malloc调用。

When a recording is loaded, the data is first presented in a table. The table shows the leaf functions calling malloc. In addition to the function name, the table shows module, count, size, and delta. This information is sampled so it is possible not all malloc / free calls will be captured. This largely depends on the sampling rate, which will be discussed a bit later.

加载记录后,数据首先显示在表格中。 该表显示了调用malloc的叶子函数。 除函数名称外,该表还显示模块,计数,大小和增量。 对该信息进行了采样,因此可能无法捕获所有的malloc / free调用。 这很大程度上取决于采样率 ,稍后将对此进行讨论。

It is also useful to know where these functions that allocate memory are being called from. There are two ways to visualize this information. The first is by changing the “Arrange by allocation method” dropdown to “Arrange by call stack”. The table shows a tree of callstacks, similar to what you may expect from a CPU recording. If the current project has symbols (which is usually the case for debuggable builds; if you’re profiling an external APK check out the guide here) they will automatically be picked up and used. This allows you to right click on a function and “Jump to source”.

了解从何处调用这些分配内存的函数也很有用。 有两种方法可以可视化此信息。 第一种是通过将“按分配方式排列”下拉列表更改为“按调用堆栈排列”。 该表显示了一个调用栈树,类似于您可能从CPU记录中看到的树。 如果当前项目中包含符号(可调试版本通常是这种情况;如果您要对外部APK进行分析,请查看此处的指南),它们将被自动使用。 这使您可以右键单击某个功能,然后单击“跳转到源代码”。

Image for post
Within the table view Right Clicking an element shows a “Jump to Source” context menu
在表格视图中,右键单击元素会显示“跳转到源代码”上下文菜单

内存可视化(本机和非本机) (Memory Visualization (Native and non-native))

We’ve also added a new flame chart visualization to the memory profilers, allowing you to quickly see what callstacks are responsible for allocating the most memory. This is especially useful when a call stack is really deep.

我们还在内存分析器中添加了新的火焰图可视化功能,使您可以快速查看哪些调用堆栈负责分配最多的内存。 当调用堆栈非常深时,这特别有用。

There are four ways you can sort this data along the X axis:

您可以通过四种方式沿X轴对这些数据进行排序:

Image for post
  • “Allocation Size” is the default, showing the total amount of memory tracked.

    默认值为“分配大小”,显示跟踪的内存总量。
  • “Allocation Count” shows the total number of objects allocated.

    “分配计数”显示分配的对象总数。
  • “Total Remaining Size” is the size of memory sampled throughout the capture that was not freed before the end of the capture.

    “总剩余大小”是在整个捕获过程中采样的,在捕获结束之前没有释放的内存大小。
  • “Total Remaining Count”, like the remaining size, is the count of objects captured but not freed before the end of the capture.

    与剩余大小一样,“剩余总数”是捕获的但在捕获结束之前未释放的对象的数量。
Image for post
With this capture loaded, in the “Total Remaining Size” view, it is easy to see “lodepng” is responsible for allocating a lot of memory.
加载此捕获后,在“总剩余大小”视图中,很容易看到“ lodepng”负责分配大量内存。

From here we can right click on the call stacks and select “Jump to Source” to take us to the line of code responsible for the allocation. However, taking a second glance at the visualization, we notice that the common parent, WorldState, is responsible for multiple leaks. To validate this, it can help to filter the results.

在这里,我们可以右键单击调用堆栈,然后选择“跳转到源代码”,将我们带到负责分配的代码行。 但是,再次看一下可视化,我们注意到公共父级WorldState导致了多次泄漏。 为了验证这一点,它可以帮助过滤结果。

筛选/导航 (Filtering / Navigation)

Like with the table view, the chart can be filtered using the filter bar. When the filter is used, the data in the chart is automatically updated to show only call stacks that have functions matching the word/regex searched.

与表格视图一样,可以使用过滤器栏过滤图表。 使用过滤器时,图表中的数据将自动更新,以仅显示具有与搜索到的单词/正则表达式匹配的功能的调用堆栈。

Image for post
After applying a filter it seems clear that WorldState is responsible for leaking ~70MB of our total assumed leak ~72MB.
应用过滤器后,似乎很明显,WorldState负责泄漏我们假定的总泄漏量〜72MB中的约70MB。

Sometimes call stacks can get fairly long, or there just isn’t enough room to display the function name on screen. To assist with this, ctrl + mouse wheel will zoom in/out, or you can click on the chart to use W,A,S,D to navigate.

有时,调用堆栈可能会变得很长,或者没有足够的空间在屏幕上显示函数名称。 为此,Ctrl +鼠标滚轮将放大/缩小,或者您可以单击图表以使用W,A,S,D进行导航。

验证结果 (Verifying the findings)

Adding a breakpoint and running the Emulation twice quickly reveals that on the second run we cause the leak by overwrite the pointer from our first run.

添加一个断点并运行两次仿真可以快速地揭示出,在第二次运行时,我们会覆盖第一次运行的指针,从而导致泄漏。

Image for post
Quick view of the debugger showing “sWorld” already has a value the 2nd time around
显示“ sWorld”的调试器的快速视图已经是第二次具有该值

As a quick fix to the sample we can delete the world after it is marked done, profiling the application again to validate the fix.

作为示例的快速修复,我们可以在标记完成后删除世界,再次对应用程序进行性能分析以验证修复。

Image for post
Memory view after running the demo two times
两次运行演示后的内存视图

Ending where we started by looking at the high level memory stats. Validating that deleting sWorld at the end of the simulation frees up the 70mb held by our first run.

通过查看高级内存统计信息来结束我们的工作。 验证在模拟结束时删除sWorld可以释放我们第一次运行所占用的70mb。

启动配置文件和采样率设置。 (Startup profiling and sample rate setting.)

The sample above shows how native memory tracking can be used to find and fix memory leaks. Another common use for native memory tracking is understanding where memory is going during startup of the application. In Android Studio 4.1, we also added the ability to capture native memory recordings from the startup of the application. This is available in the “Run/Debug Configurations” dialog under the “Profiling” tab.

上面的示例显示了如何使用本机内存跟踪来查找和修复内存泄漏。 本机内存跟踪的另一种常见用法是了解应用程序启动期间内存的去向。 在Android Studio 4.1中,我们还添加了从应用程序启动时捕获本机内存记录的功能。 这在“配置”选项卡下的“运行/调试配置”对话框中可用。

Image for post
Profiling tab located in the Run Configuration dialog.
位于“运行配置”对话框中的“分析”选项卡。

You can customize the sampling interval or record memory at startup in the Run configuration dialog.

您可以自定义采样间隔或在启动时在“运行配置”对话框中记录内存。

Here you can also change the sampling rate for new captures. A smaller sampling rate can have a large impact on overall performance, while a larger sampling rate can miss some allocations. Different sampling rates work for different types of memory problems.

在这里,您还可以更改新捕获的采样率。 较小的采样率可能会对整体性能产生较大影响,而较大的采样率可能会丢失某些分配。 不同的采样率适用于不同类型的内存问题。

结语 (Wrapping up)

With the new native memory profiler finding memory leaks and understanding where memory is being held on to just got a little bit easier. Give the native memory profiler a try in Android Studio 4.1, and leave any feedback on our bug tracker. For additional tips and tricks be sure to also check out our talk earlier this year at the Google for Games summit, Android memory tools and best practices.

使用新的本机内存探查器,可以查找内存泄漏并了解将内存保留在何处,从而变得更加容易。 在Android Studio 4.1中尝试使用本机内存分析器,并在我们的错误跟踪器上留下任何反馈 有关其他提示和技巧,请确保也请查阅我们今年早些时候在Google for Games峰会上的演讲, Android内存工具和最佳做法

翻译自: https://medium.com/androiddevelopers/native-memory-profiling-with-android-studio-4-1-33a9e6b44be

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值