其他
百度APP iOS端内存优化实践-大块内存监控方案
The following article is from 百度App技术 Author RichardYang
GEEK TALK
01
背景
GEEK TALK
02
技术方案综述
获取内存分配详情。判断单次内存分配是否超过阈值,若超过阈值,说明是大内存分配行为; 获取堆栈信息。丰富的堆栈信息可直接帮助开发同学定位到产生大内存分配的具体代码,定位分配不合理的case。
GEEK TALK
03
获取内存分配详情
3.1 方案对比
通过 hook 内存分配函数 alloc 方法获取,用 swizzle 方法实现 hook,存在的缺点是监控范围不够全面,只能监控 OC 对象,不能监控 C/C++ 对象。 hook 库libsystem_malloc 内存分配函数 malloc_zone_malloc、malloc_zone_calloc、malloc_zone_valloc、malloc_zone_realloc来获取内存信息。这种方案对于 OC 对象和 C/C++ 对象都可监控,但是因为要 hook 系统 C/C++ 方法而不是 OC 方法,目前的技术条件需要使用 fishhook。
3.2 libsystem_malloc源码分析
void *malloc_zone_malloc(malloc_zone_t *zone, size_t size){ MALLOC_TRACE(TRACE_malloc | DBG_FUNC_START, (uintptr_t)zone, size, 0, 0);void *ptr;if (malloc_check_start && (malloc_check_counter++ >= malloc_check_start)) { internal_check(); }if (size > MALLOC_ABSOLUTE_MAX_SIZE) {return NULL; } ptr = zone->malloc(zone, size); // if lite zone is passed in then we still call the lite methodsif (malloc_logger) { malloc_logger(MALLOC_LOG_TYPE_ALLOCATE | MALLOC_LOG_TYPE_HAS_ZONE, (uintptr_t)zone, (uintptr_t)size, 0, (uintptr_t)ptr, 0); } MALLOC_TRACE(TRACE_malloc | DBG_FUNC_END, (uintptr_t)zone, size, (uintptr_t)ptr, 0);return ptr;}
3.3 关键函数malloc_logger
if (malloc_logger) {
malloc_logger(MALLOC_LOG_TYPE_ALLOCATE | MALLOC_LOG_TYPE_HAS_ZONE, (uintptr_t)zone, (uintptr_t)size, 0, (uintptr_t)ptr, 0);
}
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;
3.4 通过重置malloc_logger函数指针获取内存活动详情
#import <malloc/malloc.h>
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);
//定义函数bba_malloc_stack_logger
void bba_malloc_stack_logger(uint32_t type, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t result, uint32_t backtrace_to_skip);
// 保存malloc_logger到临时变量origin_malloc_logger
orgin_malloc_logger = malloc_logger;
//malloc_logger赋值为自定义函数bba_malloc_stack_logger
malloc_logger = (malloc_logger_t *)bba_malloc_stack_logger;
//bba_malloc_stack_logger具体实现
void bba_malloc_stack_logger(uint32_t type, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t result, uint32_t backtrace_to_skip)
{
if (orgin_malloc_logger != NULL) {
orgin_malloc_logger(type, arg1, arg2, arg3, result, backtrace_to_skip);
}
//大块内存监控
......
}
if (malloc_logger) { malloc_logger(MALLOC_LOG_TYPE_ALLOCATE | MALLOC_LOG_TYPE_HAS_ZONE, (uintptr_t)zone, (uintptr_t)size, 0, (uintptr_t)ptr, 0);}
3.5 通过type类型过滤出内存分配详情
3.6 获取单次内存分配大小并判断是否超过阈值
GEEK TALK
04
获取堆栈信息
4.1 百度App采用的技术方案
4.2 生成所有库的地址范围(dyld)
4.3 backtrace获取堆栈地址
//返回值depth表示实际上获取的堆栈的深度,stacks用来存储堆栈地址信息,20表示指定堆栈深度。
size_t depth = backtrace((void**)stacks, 20);
4.4 获取每个地址详细信息
4.5 atos和dsym解析堆栈
BaiduBoxApp 0x000000010ff0ceb4 +[BBAJSONSerialization dataFromJSONObject:error:] + 256
GEEK TALK
05
总结
降低OOM率:如果内存分配不合理,优化后对降低OOM率有帮助; 数据摸底,让我们明确知道百度APP哪些场景有大块内存分配; 起到预防的作用,因为我们有明确的监控机制,督促每个开发同学创建内存对象时采用适量原则避免无节制分配。
GEEK TALK
06
参考链接
END