[MUSIC PLAYING]
BILL BILODEAU: Developers can face challenges
when using memory on Android.
The system may need to kill your game
if there isn't enough memory.
Determining a memory budget is hard
because there are no guarantees how much memory you can use.
And bad memory pointers can be hard to find.
Let's take a quick look at how Android manages memory.
Android uses memory for caching background apps,
so keeping large amounts of memory free
is just wasting memory.
If your game needs memory, you may
need to wait for Android to kill background apps.
Keep in mind that other processes may have a higher
priority memory than your game.
Here are some tips on how to handle low-memory situations.
Try to be conservative with memory.
The kernel and system processes take up memory,
so you can't use all the physical memory.
Typical user apps may start background services
that take up memory, so you shouldn't
test on a clean device.
OnTrimMemory can warn you that memory
is running low, which means that the Low Memory Killer, or LMK,
could start killing processes.
If the memory gets too low, then even your game could get
killed.
A bug report will show if your game was killed by LMK.
You can capture a bug report by using adb.bugreport command.
This saves a log which you can search for the string
lowmemorykiller to see if your game was killed by LMK.
Android Studio now has a Native Memory Profiler
to help you understand how your game uses memory.
Stack traces of memory allocations
can show where to reduce memory, and seeing de-allocations
can help you pinpoint memory leaks.
Note that it's limited to system malloc and free calls.
Therefore, you may have to make minor changes
to profiling memory usage.
Some games allocate a pool of memory
with mmap and then suballocate from these pools.
The Android Studio Memory Profiler
will miss these allocations.
To profile, use malloc and free instead of the custom
allocated functions.
This can be done in Unreal and Unity with some minor changes.
To make Unreal use the system malloc and free,
you need to modify the base allocator
method to use FMallocAnsi, as shown here.
For Unity, you can extend or modify UnityPlayerActivity
to include the systemallocator flag in the command line
arguments.
Running the Native Memory Profiler
is similar to other profiling tools in Android Studio.
>From the Memory Profile view, click on the Memory Trace.
>From the Memory Trace view, click
on "Record native allocations."
When you stop the recording, you can see the results,
and you'll see something like this.
This view shows the methods that are called allocation
functions, along with how much memory
was allocated and de-allocated.
The callstack view shows the callstack and allocations
and de-allocations.
Tencent used our heapprofd native memory profiling tool
to find memory problems in PUBG MOBILE.
heapprofd is the same memory profiling technology
that's used in Android Studio's Native Memory Profiler.
The problem was that they were seeing an unexpected memory
increase when going from a 32-bit
to a 64-bit version of the game.
In order to find out where the increase was coming from,
they needed to track native memory allocations
with reasonable performance.
Tencent used it to compare the size of structures compiled
for 32-bit versus 64-bit and found that these structures
grew by 10 megabytes because of the doubling of pointer
sizes and extra pattern.
Another type of memory problem is with bad memory pointers.
This can lead to crashes, like segmentation violations,
accessing invalid data, or in general unexpected behavior.
Some of the causes of bad memory pointers
include accessing freed memory, buffer overruns,
or just uninitialized or corrupted memory pointers.
Hardware Assisted Address Sanitizer, or Hardware ASan,
is a new tool for detecting memory pointer issues.
It's like ASan, but faster, with much less memory overhead.
When Hardware ASan is enabled, it
will cause the game to crash if an invalid pointer is used.
It uses a Hardware ASan build with Android 10
or later on Pixel phones.
Games need to be 64-bit and use malloc and free or instrumented
custom allocators.
Here is how Hardware ASan works.
It uses the Top Byte Ignore feature and ARM 64 architecture
to store a memory tag in the pointer.
It also creates a shadow memory to map allocations
to a unique tag.
If the pointer tag doesn't match the shadow memory tag,
then it knows the pointer was bad.
Here are the steps to use Hardware ASan.
First, flash a Pixel device with a Hardware ASan
version of Android.
You can get this at flash.android.com.
Look for the aosp master with phones throttled build.
You wanted to disable any use of the Google Play Services,
since it isn't compiled for Hardware ASan.
The next step is to build a Hardware ASan-enabled version
of your game.
You can do this by modifying the build.gradle and cmake
lists.txt files.
Finally, when Hardware ASan detects
that a bad memory pointer is used, the game will crash.
You can view the logcat output to see where the bad memory
access occurred and also a stack trace
of the original allocation or de-allocation in the case
of use after free bugs.
You can learn about the Native Memory Profiler on Android
Studio, memory best practices, and more
at d.android.com/games.
[MUSIC PLAYING]