background

According to the answer of Apple official WWDC, reducing the memory allows users to experience a faster startup speed, avoiding Crash caused by excessive memory, and enabling the APP to survive longer.

For AmAP, according to online data analysis, too much memory will cause the system to kill OOM during navigation. Especially different from other apps, the general APP only needs to pay attention to the foreground memory is too high system strong kill FOOM, Gaudamap has many users using background navigation, so also need to pay attention to the background memory is too high system strong kill BOOM, and the background strong kill is more serious than the foreground strong kill. In order to improve user experience, memory governance is urgent.

The principle of analyzing

OOM

OOM is short for Out of Memory. In iOS APP, if the memory is over, the system will directly kill the APP, which is a kind of alternative Crash and cannot be captured. When discovering OOM, you can choose Device > Privacy > Analysis & Improvement > Analysis Data to find the log starting with JetsamEvent, which records a lot of information: mobile device information, system version, memory size, CPU time, etc.

Jetsam

Jetsam is a resource management mechanism for iOS. Unlike MacOS, Linux, and Windows, iOS does not have memory swapping space. Therefore, when the overall memory of the device is insufficient, the system kills some devices that have low priorities or occupy too much memory.

The iOS open-source XNU kernel source code can be analyzed as follows:

  • Each process has a priority list in the kernel, and JetSam will try to kill the process with the lowest priority list when stressed by memory until the memory water level returns to normal.
  • Jetsam gets the phys_footprint value from get_task_phys_footprint to decide whether to kill the application.

The Jetsam mechanism cleanup strategy can be summarized as follows:

  • If the physical memory usage of an APP exceeds the upper limit, it will be cleared. Different devices have different memory thresholds.
  • If the physical memory usage of the entire device is under pressure, clear background applications first and then foreground applications.
  • Delete the applications with high memory usage first and then the applications with low memory usage.
  • User applications are cleaned before system applications.

Low Memory Killer on Android:

  • Depending on the priority of the APP and how much total memory is used, the system will force the APP to die if the device memory is tight.
  • The determination of memory tightness depends on the size of the system RSS, which actually uses physical memory and contains all the memory occupied by the shared libraries.
  • There are three key parameters:

1) oOM_adj: used in the Framework layer. It represents the priority of a process. The higher the value, the lower the priority and the easier it is to be killed.

2) oOM_adj threshold: used in the Framework layer, representing the memory threshold of OOM_adj. The Android Kernel periodically checks whether the current remaining memory is lower than the threshold. If the remaining memory is lower than the threshold, the process with the largest value in oOM_ADJ is killed until the remaining memory is higher than the threshold.

3) oOM_score_adj: used in the Kernel layer, converted from oom_adj, is the actual parameter used to kill processes.

The data analysis

Phys_footprint Indicates the total physical Memory of the iOS application. For details, see iOS Memory Deep Dive.

std::optional<size_t> memoryFootprint() { task\_vm\_info\_data\_t vmInfo; mach\_msg\_type\_number\_t count = TASK\_VM\_INFO_COUNT; kern\_return\_t result = task\_info(mach\_task\_self(), TASK\_VM\_INFO, (task\_info_t) &vmInfo, &count); if (result ! = KERN_SUCCESS) return std::nullopt; return static\_cast<size\_t>(vmInfo.phys_footprint); }Copy the code

The Instrument-VM Tracker can be used to analyze specific memory categories, such as the Malloc portion of heap memory, the Webkit Malloc portion of JavaScriptCore memory, and so on. Note that the memory value for each category = Dirty Size + Swapped.

The memory distribution in the Instruments VM Tracker capture navigation was compared and analyzed. When the navigation foreground is static, amap’s total memory is very high, with IOKit, WebKit Malloc, and Malloc heap being the largest memory footprint.

There are many tools that can be used in the analysis process, each of which has its own advantages and disadvantages. They need to be used together to complement each other. We used Intruments VM Tracker, Allocations, Capture GPU Frame, MemGraph, Dumpsys meminfo, Graphics API Debugger, Arm primarily in our analysis Mobile Studio, AJX memory analysis tool, self-developed Malloc analysis tool, etc.

  • IOKit memory for map rendering video memory part.
  • WebKit Malloc memory is AJX JS business memory.
  • Malloc heap memory, we use the Hook Malloc API to allocate memory, by fetching the stack analysis of specific memory consumers.

Management optimization

Based on the data above, it’s easy to start with the big head. Our general idea in the process of governance:

  • Analyze data: Starting from the memory size, analyze the services that each memory belongs to for further analysis and optimization.
  • Memory governance: Optimize the technical solution to reduce memory overhead, function hierarchy of high – and low-end servers, and intelligent DISASTER recovery (THAT is, release memory by function degradation when a memory alarm is generated).

Divide and conquer

According to data analysis, the three major memory consumption of Autonavi are map rendering (Graphic memory), functional business (JavaScriptCore) and general business (Malloc). We also mainly optimize from these three aspects.

Map Graphic memory optimization

Xcode provides the debugging tool Capture GPU Frame to analyze the memory usage. The memory usage is divided into Texture and Buffer, and the specific memory consumption is analyzed based on the detailed address information. Android side similar to analysis of video memory tools can use Google Graphics API Debugger.

According to the analysis, in the section of Texture, we reduced the video memory consumption by adjusting the FBO drawing mode, optimizing the background of the large picture of vector intersection, releasing ICONS across pages, optimizing the text Texture, closing the low-end full-screen anti-aliasing, etc. In the Buffer part, low video memory mode is enabled, quad tree preloading is disabled, and cache resources are released by cutting the background.

Its Malloc optimization

Amap uses a dynamic solution developed by itself and relies on JavaScriptCore, the framework provided by iOS. Most of the business memory consumption is classified by the system into WebKit Malloc, as can be seen from VM Tracker on system Tools Instruments. There are two ideas here, one is to optimize memory consumption for the business itself, and the second is to dynamically optimize memory consumption for the engine and framework.

Business optimization, dynamic solution IDE provides memory analysis tools can clearly output specific business memory consumption in what place, convenient business students analysis is reasonable.

Dynamic engine and framework optimization, we optimize the way of using the system library JavaScriptCore, that is, multiple JSContextRef contexts share the same JSContextGroupRef. Multiple pages can share a copy of framework code, reducing memory overhead.

Malloc heap memory optimization

The libmalloc library is used for iOS heap memory allocation, which contains the following interfaces:

/ / c allocation methods void * malloc (size \ _t \ _ \ _size) \ _ \ _result \ _use \ _check \ _ \ _alloc_size (1); Void * calloc (size \ _t \ _ \ _count, size \ _t \ _ \ _size) \ _ \ _result \ _use \ _check \ _ \ _alloc_size (1, 2); void free(void *); void \*realloc(void \*\_\_ptr, size\_t \_\_size) \_\_result\_use\_check \_\_alloc\_size(2); void *valloc(size\_t) \_\_alloc_size(1); // Create a heap based copy of a block or simply add a reference to an existing one. // This must be paired  with Block_release to recover memory, even when running // under Objective-C Garbage Collection. BLOCK\_EXPORT void \*\_Block_copy(const void \*aBlock) \_\_OSX\_AVAILABLE\_STARTING(\_\_MAC\_10\_6, \_\_IPHONE\_3_2);Copy the code

The memory usage can be analyzed by recording the stack and size of memory allocation through hook memory operation API.

Malloc_logger is a global hook function that can output logs in the Malloc process.

// We set malloc_logger to NULL to disable logging, if we encounter errors
// during file writing
typedef void(malloc\_logger\_t)(uint32_t type,
        uintptr_t arg1,
        uintptr_t arg2,
        uintptr_t arg3,
        uintptr_t result,
        uint32\_t num\_hot\_frames\_to_skip);
extern malloc\_logger\_t *malloc_logger;
Copy the code

IOS heap memory analysis program, can be achieved through hook MALloc series API, can also set malloc_logger function, can record the heap memory usage.

There are several difficulties in this scheme, such as the magnitude of memory allocation per second and the need for efficient query and stack unaggregation. Therefore, we designed a complete Malloc heap memory analysis scheme to quickly locate the heap memory ownership and distribute it to the respective business Owner for analysis and optimization.

Unified management

As business growth has brought great resource pressure to amap, a super APP, we have developed an adaptive resource management framework to achieve the ultimate balance of functions and experience in different business scenarios with limited resources. The main design idea is to monitor the user’s device level, system status, current business scenarios and user behavior, use scheduling algorithm to make real-time calculation, unified management and coordination of the current resource state allocation of APP, and recover the user’s currently invisible resources such as memory.

Adaptive resource Management framework – Memory section

Resources can be managed based on different device levels, service scenarios, user behaviors, and system status. All businesses can easily access this framework, and it has been applied to many business scenarios with good benefits.

Data inspection and acceptance

Through three successive versions of governance, both front and back navigation scenarios have 50% benefits, and Abort rates also have 10% to 20% benefits. The overall earnings are positive, but the challenge is how do we sustain those gains.

Long term control

If there is no long-term control plan, with the iteration of the version of the business, the previous optimization will be consumed in less than three or five versions. To this end, we built a set of APM performance monitoring platform to find and solve problems in the development and testing stage, without bringing problems online.

APM performance monitoring platform

In order to monitor APP performance daily, we built a set of offline “APM Performance Monitoring platform”, which can support performance monitoring of routine business scenarios, including memory, CPU, flow, etc., and timely find problems and alarm. Then with the performance follow up process, for the client performance guarantee to the last pass.

Memory analysis tool

Xcode Memory Gauge: In the Debug Navigator of Xcode, you can roughly check the memory usage.

Instruments – Allocations: You can view virtual memory Allocations, heap information, object information, call stack information, VM Regions information, and more. You can use this tool to analyze memory and optimize it for local.

Leaks: Used to detect memory Leaks.

This tool allows you to view the memory usage of different types of memory, such as the size of dirty memory, to help analyze the cause of excessive memory and memory leaks.

For details about Memory paging, see WWDC 2016-syetem Trace in Depth.

Memory Resource Exceptions: Starting with Xcode 10, when Memory usage is too high, the debugger can catch EXC_RESOURCE RESOURCE_TYPE_MEMORY Exceptions and break them where the exception is thrown.

Xcode Memory Debugger: In Xcode, you can directly view the interdependencies between all objects. It is very convenient to find problems with cyclic references. You can also export this information as a memgraph file.

Memgraph + command line instructions: With the memgraph file output in the previous step, you can analyze memory with a few instructions. Vmmap displays process information and VMRegions information. You can view information about a specified VMRegion with grep. Leaks traces objects in the heap to see memory leaks, stack information, and more. The heap prints all the information in the heap, making it easy to track objects that have a large footprint. Malloc_history makes it easy to find problems by looking at the stack information for objects that are produced by the heap directive.

Malloc_history ===> Creation; Leaks = = = > the Reference; Heap & vmmap ===> Size.

MetricKit: A new monitoring framework for iOS 13 that collects and processes battery and performance metrics. When users use the APP, iOS will record various indicators, and then send them to apple server, and automatically generate relevant visual reports. The Organizer can be checked by Window -> Organizer -> Metrics, including battery, boot time, lag, memory, disk read and write. MetricKit can also be integrated into a project and upload data to its own service for analysis.

MLeaksFinder: Can detect memory leaks without breaking code by determining if all its children are destroyed after the UIViewController is destroyed.

Graphics API Debugger: A series of Google open source Graphics debugging tools that can examine, fine-tune, and replay applications’ graphics-driven API calls.

Arm Mobile Studio: Professional GPU analysis tool.