Android内存优化(二)之获取native heap文件过程

获取某个进程native heap的方法大致分为两个步骤:
1:配置两个属性,上一篇博客中有介绍,具体操作如下:
adb shell stop
adb shell setprop libc.debug.malloc.program app_process
adb shell setprop libc.debug.malloc.options backtrace
adb shell start
2:shell命令dump native heap
adb shell am dumpheap -n [pkg]

执行流如下:
onCommand (ActivityManagerShellCommand.java)
runDumpHeap(ActivityManagerShellCommand.java)
dumpHeap(ActivityThread.java)
handleDumpHeap(ActivityThread.java)
dumpNativeHeap(Debug.java)
android_os_Debug_dumpNativeHeap(android_os_debug.cpp)
dumpNativeHeap(android_os_debug.cpp)
get_malloc_leak_info(malloc_common.cpp)

在README_api.md文件中有一段描述:

Malloc debug can be used to get information on all of the live allocations
in a process. The libc library in Android exports two calls that can be
used to gather this data from a process. This tracking can be enabled using
either the backtrace option or the backtrace\_enabled\_on\_signal option.

The function to gather the data:

`extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overall_size, size_t* info_size, size_t* total_memory, size_t* backtrace_size);`

意思是malloc debug可以用来获取进程的所有内存分配的现场信息,libc中有两种方式可以收集这些信息,一个是backtrace option,一个是backtrace_enabled_on_signal option,而获取这些内存分配现场的接口,就是get_malloc_leak_info~

看下这个接口的实现:
extern “C” void get_malloc_leak_info(uint8_t** info, size_t* overall_size,
size_t* info_size, size_t* total_memory, size_t* backtrace_size) {
if (g_debug_get_malloc_leak_info_func == nullptr) {
return;
}
g_debug_get_malloc_leak_info_func(info, overall_size, info_size, total_memory, backtrace_size);
}
get_malloc_leak_info会进而调用到g_debug_get_malloc_leak_info_func(malloc_common.cpp) 方法(如果g_debug_get_malloc_leak_info_func没有初始化,直接return,这时获取的内容为空)。g_debug_get_malloc_leak_info_func方法则是在上篇文章有提到,是在malloc debug初始化时初始化的一个方法指针:

  g_debug_get_malloc_leak_info_func = reinterpret_cast<void (*)(
      uint8_t**, size_t*, size_t*, size_t*, size_t*)>(get_leak_info_sym);

只是做了下函数指针转换,看一下函数指针get_leak_info_sym:

  void* get_leak_info_sym = dlsym(malloc_impl_handle, "debug_get_malloc_leak_info");

dlsym的作用就是通过共享库的handle找到对应函数的地址,这个handle就是malloc_budeg共享库的handle

  static const char* DEBUG_SHARED_LIB = "libc_malloc_debug.so";
  // Load the debug malloc shared library.
  void* malloc_impl_handle = dlopen(DEBUG_SHARED_LIB, RTLD_NOW | RTLD_LOCAL);

可以简单理解:g_debug_get_malloc_leak_info_func就是debug_get_malloc_leak_info方法,看下debug_get_malloc_leak_info实现

void debug_get_malloc_leak_info(uint8_t** info, size_t* overall_size,
    size_t* info_size, size_t* total_memory, size_t* backtrace_size) {
  ScopedDisableDebugCalls disable;

  // Verify the arguments.
  if (info == nullptr || overall_size == nullptr || info_size == NULL ||
      total_memory == nullptr || backtrace_size == nullptr) {
    error_log("get_malloc_leak_info: At least one invalid parameter.");
    return;
  }

  *info = nullptr;
  *overall_size = 0;
  *info_size = 0;
  *total_memory = 0;
  *backtrace_size = 0;

  if (!(g_debug->config().options & BACKTRACE)) {
    error_log("get_malloc_leak_info: Allocations not being tracked, to enable "
              "set the option 'backtrace'.");
    return;
  }

  g_debug->track->GetInfo(info, overall_size, info_size, total_memory, backtrace_size);
}

如果已经配置backtrace,则会调用到g_debug->track->GetInfo,g_debug->track是TrackData类型,是在DebugData.cpp中DebugData::Initialize方法中初始化的(上篇有张有提到),看下TrackData::GetInfo方法:

void TrackData::GetInfo(uint8_t** info, size_t* overall_size, size_t* info_size,
                        size_t* total_memory, size_t* backtrace_size) {
  ScopedPthreadMutexLocker scoped(&mutex_);

  if (headers_.size() == 0 || total_backtrace_allocs_ == 0) {
    return;
  }

  *backtrace_size = debug_->config().backtrace_frames;
  *info_size = sizeof(size_t) * 2 + sizeof(uintptr_t) * *backtrace_size;
  *info = reinterpret_cast<uint8_t*>(g_dispatch->calloc(*info_size, total_backtrace_allocs_));
  if (*info == nullptr) {
    return;
  }
  *overall_size = *info_size * total_backtrace_allocs_;

  std::vector<const Header*> list;
  GetList(&list);

  uint8_t* data = *info;
  size_t num_allocations = 1;
  for (const auto& header : list) {
    BacktraceHeader* back_header = debug_->GetAllocBacktrace(header);
    if (back_header->num_frames > 0) {
      memcpy(data, &header->size, sizeof(size_t));
      memcpy(&data[sizeof(size_t)], &num_allocations, sizeof(size_t));
      memcpy(&data[2 * sizeof(size_t)], &back_header->frames[0],
            back_header->num_frames * sizeof(uintptr_t));

      *total_memory += header->real_size();

      data += *info_size;
    }
  }
}

再看下GetList方法:

void TrackData::GetList(std::vector<const Header*>* list) {
  for (const auto& header : headers_) {
    list->push_back(header);
  }

  // Sort by the size of the allocation.
  std::sort(list->begin(), list->end(), [](const Header* a, const Header* b) {
    if (a->size == b->size) return a < b;
    return a->size > b->size;
  });
}

这个headers_是什么呢?就是我们上一篇文章:Android内存优化(二)之malloc debug简单介绍与初始化工作 提到的mallo时通过调用TrackData::Add方法添加的~

猜你喜欢

转载自blog.csdn.net/longlong2015/article/details/80533946