In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-04-08 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/02 Report--
Today I'll show you what the systematic solution to AndroidNative memory leaks is. The content of the article is good. Now I would like to share it with you. Friends who feel in need can understand it. I hope it will be helpful to you. Let's read it along with the editor's ideas.
Introduction: the analysis and location of C++ memory leak has always been a difficult problem for developers on the Android platform. Because the core functions such as map rendering and navigation require high performance, there is a lot of C++ code in Amap APP. To solve this problem is particularly important and critical to product quality. Amap's technical team has formed a set of its own solution in practice.
The core of analyzing and locating memory leaks lies in the statistics of allocation functions and stack backtracking. If you only know the memory allocation point and do not know the call stack, it will make the problem particularly complex and increase the cost of solving, so both are indispensable.
The malloc_debug module of Bionic in Android is perfect in monitoring and statistics of memory allocation function, but stack backtracking is lack of efficient way in Android system. With the development of Android, Google also provides some analysis methods for stack backtracking, but these schemes have the following problems:
1. Libunwind is used in stack backtracking, which consumes a lot. In the case of too much Native code, frequent calls will make the application very stuck, and the call stack for monitoring all memory operation functions requires frequent calls to libunwind-related functions.
two。 There are restrictions on ROM requirements, which brings inconvenience to daily development and testing.
3. Use the command line or DDMS to operate, each time you need to prepare the environment, manual operation, the final result is not intuitive, and lack of comparative analysis.
Therefore, how to carry out efficient stack backtracking and build a systematic Android Native memory analysis system is particularly important.
Amap has made some improvements and extensions based on these two points. Through these improvements, these problems can be found and solved in time through automated testing, which can greatly improve the development efficiency and reduce the cost of troubleshooting.
Stack backtracking acceleration
Libunwind is mainly used for stack backtracking on Android platform, which can satisfy most cases. However, the global lock and unwind table parsing in libunwind implementation will have performance loss, which will lead to the application card change and can not be used in the case of frequent calls from multi-threads.
Acceleration principle
The compiler's-finstrument-functions compilation option allows you to insert custom functions at the beginning and end of functions at compile time, a call to _ _ cyg_profile_func_enter at the beginning of each function, and a call to _ _ cyg_profile_func_exit at the end. The call point address can be obtained in these two functions, and the function call stack can be obtained at any time by recording these addresses.
Example of the effect after inserting piles:
It is important to note here that some functions that do not require stuffing can be declared to the compiler using _ _ attribute__ ((no_instrument_function)).
How do I record these calls? We want to enable this information to be read between different threads without being affected. One way is to use a thread synchronization mechanism, such as adding a critical section or mutex where the variable is read and written, but this will affect efficiency.
Can you leave it unlocked? At this point, thread local storage, or TLS for short, comes to mind. TLS is a dedicated storage area that can only be accessed by its own threads, and there is no thread safety problem, which is consistent with the scenario here.
Therefore, the compiler is used to record the call stack and store it in the thread local storage to achieve stack backtracking acceleration. The specific implementation is as follows:
1. Use the compiler's-finstrument-functions compilation option to insert the relevant code during the compilation phase.
The record of the call address in 2.TLS is in the form of array + cursor to achieve the fastest insertion, deletion and acquisition.
Define the data structure of array + cursor:
Typedef struct {void* Stack [Max _ TRACE_DEEP]; int current;} thread_stack_t
Initialize the storage key for thread_stack_t in TLS:
Static pthread_once_t sBackTraceOnce = PTHREAD_ONCE_INIT; static void _ attribute__ ((no_instrument_function)) destructor (void* ptr) {if (ptr) {free (ptr);}} static void _ attribute__ ((no_instrument_function)) init_once (void) {pthread_key_create (& sBackTraceKey, destructor);}
Initialize thread_stack_t and put it in TLS:
Get_backtrace_info () {thread_stack_t* ptr = (thread_stack_t*) pthread_getspecific (sBackTraceKey); if (ptr) return ptr; ptr = (thread_stack_t*) malloc (sizeof (thread_stack_t)); ptr- > current = MAX_TRACE_DEEP-1; pthread_setspecific (sBackTraceKey, ptr); return ptr;}
3. Implement _ _ cyg_profile_func_enter and _ _ cyg_profile_func_exit, and record the call address to TLS.
Void _ attribute__ ((no_instrument_function)) _ cyg_profile_func_enter (void* this_func, void* call_site) {pthread_once (& sBackTraceOnce, init_once); thread_stack_t* ptr = get_backtrace_info (); if (ptr- > current > 0) ptr- > Stack [PTR-> current--] = (void*) ((long) call_site-4) } void _ attribute__ ((no_instrument_function)) _ cyg_profile_func_exit (void* this_func, void* call_site) {pthread_once (& sBackTraceOnce, init_once); thread_stack_t* ptr = get_backtrace_info (); if (+ + ptr- > current > = MAX_TRACE_DEEP) ptr- > current = MAX_TRACE_DEEP-1;}}
The second parameter call_site of _ _ cyg_profile_func_enter is the code segment address of the calling point. When the function enters, record it in the array that has been allocated in TLS. Move the cursor ptr- > current to the left, and wait for the function to exit the cursor ptr- > current to the right.
Logical diagram:
The difference between the recording direction and the array growth direction is that the external interface to obtain stack information is more concise and efficient. Memory copy can be performed directly to obtain the call stack in which the address of the nearest call point comes first and the address of the farthest call point comes last.
4. Provides an interface to get stack information.
Get_tls_backtrace (void** backtrace, int max) {pthread_once (& sBackTraceOnce, init_once); int count = max; thread_stack_t* ptr = get_backtrace_info (); if (MAX_TRACE_DEEP-1-ptr- > current)
< count) { count = MAX_TRACE_DEEP - 1 - ptr->Current;} if (count > 0) {memcpy (backtrace, & ptr- > Stack [PTR-> current + 1], sizeof (void *) * count);} return count;}
5. Compile the above logic into a dynamic library, and other business modules rely on the dynamic library to compile, and add-finstrument-functions to the compilation flag to insert piles, so that all function calls are recorded in TLS, and users can call get_tls_backtrace (void** backtrace, int max) anywhere to get the call stack.
Effect comparison (using Google's benchmark for performance test, mobile phone model: Huawei Imagination 5SP5. 1 system):
Libunwind single thread
Single thread acquisition in TLS mode
Libunwind 10 threads
10 threads in TLS mode
From the above statistical charts, we can see that in single-thread mode, this method is 10 times faster than libunwind stack, and 50-60 times faster than libunwind stack in the case of 10 threads.
Advantages and disadvantages
Advantages: the speed is greatly improved to meet the speed requirements of more frequent stack backtracking.
Disadvantages: compiler stuffing, larger size, can not be directly used as online products, only for memory test packages. This problem can be solved by means of continuous integration. Each time the project comes out of the library, the C++ project will output the common database and the corresponding memory test library.
II. Systematization
The pain point problem of slow memory allocation stack can be solved after the above steps. Combined with the tools provided by Google, such as DDMS, adb shell am dumpheap-n pid / data/local/tmp/heap.txt command and so on, the troubleshooting of Native memory leakage can be realized, but the troubleshooting efficiency is low and requires some preparation of mobile phone environment.
Therefore, we decided to build a whole set of systematic system, which can solve such problems more conveniently. Here are the overall ideas:
Memory monitoring uses the malloc_debug module of LIBC. Do not use the official way to turn on this function, it is troublesome and not conducive to automated testing, you can compile a copy and put it in your own project, hook all memory functions, and jump to malloc_debug 's monitoring function leak_xxx to execute, so that malloc_debug monitors all memory requests / releases and makes corresponding statistics. Using get_tls_backtrace to implement the _ _ LIBC_HIDDEN__ int32_t get_backtrace_external (uintptr_t* frames, size_t max_depth) used in the malloc_debug module happens to be combined with the stack backtracking acceleration mentioned above. Establish Socket communication, support external programs to exchange data through Socket, so as to obtain memory data more easily. Set up the Web side, and the data obtained from memory can be parsed and displayed after uploading. Here, the address needs to be solved with addr2line. Write test Case, combined with automated testing. At the beginning of the test, the memory information is collected and stored through Socket. At the end of the test, the information is uploaded to the platform for parsing, and an evaluation email is sent. When there is a problem with the alarm, the R & D students can troubleshoot the problem directly through the memory curve and call stack information on the web side.
This is the whole content of what is the systematic solution to AndroidNative memory leak. For more information about what is the systematic solution to AndroidNative memory leak, you can search the previous article or browse the following article to learn! I believe the editor will add more knowledge to you. I hope you can support it!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.