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方法添加的~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章