15.優(yōu)化 - memory hook(matrix malloc hook)

??Matrix 中的 memory hook 也是基于 xhook 的實(shí)現(xiàn)的,可以記錄 malloc、calloc、free、mmap 等函數(shù)的調(diào)用。

1.初始化

??初始化主要做了二件事,一是 hook 函數(shù)的調(diào)用,二是開啟了一個(gè) while(true) 線程將記錄的數(shù)據(jù)由一組容器轉(zhuǎn)移變換到另一組容器中。

JNIEXPORT void JNICALL
Java_com_tencent_matrix_hook_memory_MemoryHook_installHooksNative(JNIEnv* env, jobject thiz,
                                                                  jobjectArray hook_so_patterns,
                                                                  jobjectArray ignore_so_patterns,
                                                                  jboolean enable_debug) {
    // 開啟線程
    memory_hook_init();
    xhook_block_refresh();
    {
        jsize size = env->GetArrayLength(hook_so_patterns);
        for (int i = 0; i < size; ++i) {
            auto jregex = (jstring) env->GetObjectArrayElement(hook_so_patterns, i);
            const char* regex = env->GetStringUTFChars(jregex, nullptr);
            // hook 函數(shù)調(diào)用
            hook(regex);
            env->ReleaseStringUTFChars(jregex, regex);
        }
    }
    ...
    xhook_grouped_ignore(HOOK_REQUEST_GROUPID_MEMORY, ".*/libandroid_runtime\\.so$", nullptr);
    xhook_unblock_refresh();
}
  • hook 函數(shù)調(diào)用
static void hook(const char *regex) { // regex 是 hook 哪個(gè) so 的名字,

    for (auto f : HOOK_MALL_FUNCTIONS) {
        int ret = xhook_grouped_register(HOOK_REQUEST_GROUPID_MEMORY, regex, f.name, f.handler_ptr, f.origin_ptr);
        LOGD(TAG, "hook fn, regex: %s, sym: %s, ret: %d", regex, f.name, ret);
    }
    LOGD(TAG, "mmap enabled ? %d", enable_mmap_hook);
    // 是否 hook mmap
    if (enable_mmap_hook) {
        for (auto f: HOOK_MMAP_FUNCTIONS) {
            xhook_grouped_register(HOOK_REQUEST_GROUPID_MEMORY, regex, f.name, f.handler_ptr, f.origin_ptr);
        }
    }
}

// 其中需要 hook 的函數(shù)有如下
// 與開辟、釋放空間相關(guān)的
const HookFunction HOOK_MALL_FUNCTIONS[] = {
        {"malloc", (void *) h_malloc, NULL},
        {"calloc", (void *) h_calloc, NULL},
        {"realloc", (void *) h_realloc, NULL},
        {"free", (void *) h_free, NULL},
        {"memalign", (void *) HANDLER_FUNC_NAME(memalign), NULL},
        {"posix_memalign", (void *) HANDLER_FUNC_NAME(posix_memalign), NULL},
        // CXX functions
#ifndef __LP64__
        ...
#else
        {"_Znwm",                               (void*) HANDLER_FUNC_NAME(_Znwm), NULL},
        {"_ZnwmSt11align_val_t",                (void*) HANDLER_FUNC_NAME(_ZnwmSt11align_val_t), NULL},
        {"_ZnwmSt11align_val_tRKSt9nothrow_t",  (void*) HANDLER_FUNC_NAME(_ZnwmSt11align_val_tRKSt9nothrow_t), NULL},
        {"_ZnwmRKSt9nothrow_t",                 (void*) HANDLER_FUNC_NAME(_ZnwmRKSt9nothrow_t), NULL},

        {"_Znam",                               (void*) HANDLER_FUNC_NAME(_Znam), NULL},
        {"_ZnamSt11align_val_t",                (void*) HANDLER_FUNC_NAME(_ZnamSt11align_val_t), NULL},
        {"_ZnamSt11align_val_tRKSt9nothrow_t",  (void*) HANDLER_FUNC_NAME(_ZnamSt11align_val_tRKSt9nothrow_t), NULL},
        {"_ZnamRKSt9nothrow_t",                 (void*) HANDLER_FUNC_NAME(_ZnamRKSt9nothrow_t), NULL},

        {"_ZdlPvm",                             (void*) HANDLER_FUNC_NAME(_ZdlPvm), NULL},
        {"_ZdlPvmSt11align_val_t",              (void*) HANDLER_FUNC_NAME(_ZdlPvmSt11align_val_t), NULL},
        {"_ZdaPvm",                             (void*) HANDLER_FUNC_NAME(_ZdaPvm), NULL},
        {"_ZdaPvmSt11align_val_t",              (void*) HANDLER_FUNC_NAME(_ZdaPvmSt11align_val_t), NULL},
#endif
        {"_ZdlPv",                              (void*) HANDLER_FUNC_NAME(_ZdlPv), NULL},
        {"_ZdlPvSt11align_val_t",               (void*) HANDLER_FUNC_NAME(_ZdlPvSt11align_val_t), NULL},
        {"_ZdlPvSt11align_val_tRKSt9nothrow_t", (void*) HANDLER_FUNC_NAME(_ZdlPvSt11align_val_tRKSt9nothrow_t), NULL},
        {"_ZdlPvRKSt9nothrow_t",                (void*) HANDLER_FUNC_NAME(_ZdlPvRKSt9nothrow_t), NULL},

        {"_ZdaPv",                              (void*) HANDLER_FUNC_NAME(_ZdaPv), NULL},
        {"_ZdaPvSt11align_val_t",               (void*) HANDLER_FUNC_NAME(_ZdaPvSt11align_val_t), NULL},
        {"_ZdaPvSt11align_val_tRKSt9nothrow_t", (void*) HANDLER_FUNC_NAME(_ZdaPvSt11align_val_tRKSt9nothrow_t), NULL},
        {"_ZdaPvRKSt9nothrow_t",                (void*) HANDLER_FUNC_NAME(_ZdaPvRKSt9nothrow_t), NULL},

        {"strdup", (void*) HANDLER_FUNC_NAME(strdup), (void **) ORIGINAL_FUNC_NAME(strdup)},
        {"strndup", (void*) HANDLER_FUNC_NAME(strndup), (void **) ORIGINAL_FUNC_NAME(strndup)},
};
// 與 mmap 相關(guān)的
static const HookFunction HOOK_MMAP_FUNCTIONS[] = {
        {"mmap", (void *) h_mmap, NULL},
        {"munmap", (void *) h_munmap, NULL},
        {"mremap", (void *) h_mremap, NULL},
#if __ANDROID_API__ >= __ANDROID_API_L__
        {"mmap64", (void *) h_mmap64, NULL},
#endif
};

// 轉(zhuǎn)換前
int ret = xhook_grouped_register(HOOK_REQUEST_GROUPID_MEMORY, regex, f.name, f.handler_ptr, f.origin_ptr);
// 實(shí)際 hook
int ret = xhook_grouped_register(HOOK_REQUEST_GROUPID_MEMORY, ".*library-not-exists\\.so$",malloc, (void *) h_malloc, NULL);

而實(shí)際調(diào)用的 h_malloc 函數(shù)也需要進(jìn)行一點(diǎn)點(diǎn)轉(zhuǎn)化才可以得到

DEFINE_HOOK_FUN(void *, malloc, size_t __byte_count) {
    CALL_ORIGIN_FUNC_RET(void*, p, malloc, __byte_count);
    LOGI(TAG, "+ malloc %p", p);
    DO_HOOK_ACQUIRE(p, __byte_count);
    return p;
}
// 將上面的代碼進(jìn)行宏替換后得到
fn_malloc_t orig_malloc;
void * h_malloc(size_t __byte_count){
    if(!orig_malloc){
        void *handle = dlopen("libc.so", 0x00001);
        if(handle){
            orig_malloc = (fn_malloc_t)dlsym(handle,malloc)
        }
    }
    void* p = orig_malloc(__byte_count);
    LOGI(TAG, "+ malloc %p", p);
    void * __caller_addr = __builtin_return_address(0);
    on_alloc_memory(caller, p, __byte_count);
    return p;
}

當(dāng)調(diào)用相關(guān) hook 函數(shù)后,先通過(guò) dlopen 打開 libc.so ,在拿到 libc.so 里面的 malloc 原函數(shù),先調(diào)用原函數(shù),拿到 hook 函數(shù)的返回地址之后再通過(guò) on_alloc_memory 函數(shù)來(lái)記錄 原malloc 函數(shù)的返回地址,開辟的大小及 hook 函數(shù)的返回地址。

  • 開啟一個(gè)線程,memory_hook_init
// memory_meta_container 構(gòu)造函數(shù) 舒適化了 ptr_meta_containers、stack_meta_containers 這二個(gè)容器
static memory_meta_container m_memory_meta_container;
//    memory_meta_container() {
//        size_t cap = ptr_meta_capacity();// 1
//        ptr_meta_containers.reserve(cap);// 申請(qǐng)n個(gè)元素的內(nèi)存空間
//        for (int i = 0; i < cap; ++i) {
//            ptr_meta_containers.emplace_back(new ptr_meta_container_wrapper_t);
//        }
//
//        cap = stack_meta_capacity();// 1
//        stack_meta_containers.reserve(cap);
//        for (int i = 0; i < cap; ++i) {
//            stack_meta_containers.emplace_back(new stack_container_wrapper_t);
//        }
//    }

// BufferManagement 構(gòu)造函數(shù)中將容器 containers_ 初始化并添加了 1<<8 個(gè) BufferQueueContainer() 對(duì)象
static BufferManagement m_memory_messages_containers_(&m_memory_meta_container);
//    BufferManagement::BufferManagement(memory_meta_container *memory_meta_container) {
//
//        containers_.reserve(MAX_PTR_SLOT);// 1<<8
//        for (int i = 0; i < MAX_PTR_SLOT; ++i) {
//            auto container = new BufferQueueContainer();
//            containers_.emplace_back(container);
//        }
//        memory_meta_container_ = memory_meta_container;
//    }

// 調(diào)用的是這里
void memory_hook_init() {
    m_memory_messages_containers_.start_process();
}

    void BufferManagement::start_process() {
        if (processing_) return;
        processing_ = true;
        pthread_create(&thread_, nullptr,
                       reinterpret_cast<void *(*)(void *)>(&BufferManagement::process_routine),
                       this);
        pthread_detach(thread_);
    }

    // 數(shù)據(jù)由 BufferManagement::containers_ 容器轉(zhuǎn)移變化到了 BufferManagement::memory_meta_container_ 里面
    // 而 BufferManagement::memory_meta_container_ 是個(gè)靜態(tài)對(duì)象
    [[noreturn]] void BufferManagement::process_routine(BufferManagement *this_) {
        size_t last_total_message_counter = 0;
        size_t total_message_counter = 0;
        while (true) {
            if (!this_->queue_swapped_) this_->queue_swapped_ = new BufferQueue(SIZE_AUGMENT); // 192

            size_t busy_queue = 0;
            for (auto container : this_->containers_) { // 遍歷 1<<8 個(gè)對(duì)象
                HOOK_LOG_ERROR("Process routine ... ");
                BufferQueue *swapped = nullptr;
                {
                    std::lock_guard<std::mutex> lock(container->mutex_);
                    if (container->queue_ && !container->queue_->empty()) { // 判斷是否為空,不為空就將其 queue_ 賦值給 queue_swapped_ 并將原來(lái)的值清空
                        HOOK_LOG_ERROR("Swap queue ... ");
                        // 將數(shù)據(jù)賦值給 swapped,并且把 container 里面的數(shù)據(jù)置空
                        swapped = container->queue_;
                        container->queue_ = this_->queue_swapped_;
                    }
                }

                if (swapped && swapped->size() >= 5) {
                    busy_queue++;
                }
                if (swapped) {
                    HOOK_LOG_ERROR("Swapped ... ");
                    swapped->process( // 依次取出 messages_ 和 allocation_message_t 記錄的信息
                            // 依次拿到記錄在 container 內(nèi)的 messages_ 和 allocations_ 容器 里面的內(nèi)容
                            [&](message_t *message, allocation_message_t *allocation_message) {

                                total_message_counter++;
                                if (message->type == message_type_allocation || message->type == message_type_reallocation ||
                                    message->type == message_type_mmap) {

                                    if (UNLIKELY(allocation_message == nullptr)) {
                                        CRITICAL_CHECK(allocation_message);
                                        return;
                                    }

                                    uint64_t stack_hash = 0;
                                    // 開辟大小不為 0 且 有 native stack 就 hash
                                    // 之前 wechat backtrace  工具記錄的
                                    if (allocation_message->size != 0 &&
                                        allocation_message->backtrace.frame_size != 0) {
                                        stack_hash = hash_frames(
                                                allocation_message->backtrace.frames,
                                                allocation_message->backtrace.frame_size);
                                    }
                                    // 一個(gè) static obj
                                    // 有一樣的 native stack 的話就放在一個(gè)類似與鏈表的地方,沒(méi)有的話就新建一個(gè)  像 HashMap<String,LinkArray>?
                                    // 返回插入的 ptr 和 stack 對(duì)象給這邊add數(shù)據(jù),對(duì)飲之前的 messages_ 和 allocation_message_t 對(duì)象
                                    // memory_meta_container_ 是一個(gè)靜態(tài)變量
                                    this_->memory_meta_container_->insert(
                                            reinterpret_cast<const void *>(allocation_message->ptr),
                                            stack_hash,
                                            allocation_message,
                                            [&](ptr_meta_t *ptr_meta, stack_meta_t *stack_meta) {  // 回調(diào)填充數(shù)據(jù)
                                                ptr_meta->ptr = reinterpret_cast<void *>(allocation_message->ptr);
                                                ptr_meta->size = allocation_message->size;
                                                ptr_meta->attr.is_mmap =
                                                        message->type == message_type_mmap;

                                                if (UNLIKELY(!stack_meta)) {
                                                    ptr_meta->caller = allocation_message->caller;
                                                    return;
                                                }

                                                stack_meta->size += allocation_message->size;
                                                if (stack_meta->backtrace.frame_size == 0 &&
                                                    allocation_message->backtrace.frame_size != 0) {
                                                    stack_meta->backtrace = allocation_message->backtrace;
                                                    stack_meta->caller = allocation_message->caller;
                                                }
                                            });
                                } else if (message->type == message_type_deletion ||
                                           message->type == message_type_munmap) {
                                    this_->memory_meta_container_->erase(
                                            reinterpret_cast<const void *>(message->ptr));
                                }
                            });
                    //  messages_ 及 allocations_ 容器置空
                    swapped->reset();
                    this_->queue_swapped_ = swapped;
                }
            }
        }
    }

總結(jié):將數(shù)據(jù)由 BufferManagement::containers_ 容器轉(zhuǎn)移到了 BufferManagement::memory_meta_container_ 里面。

2.hook 記錄相關(guān)信息

??分析 malloc 及 free 這二個(gè)函數(shù) hook 之后記錄的信息。

  • 1.malloc hook
    ??在初始化中提到 malloc 的 hook 函數(shù)是 h_malloc,而該函數(shù)通過(guò) dlopen 打開 libc.so ,在拿到 libc.so 里面的 malloc 原函數(shù),先調(diào)用原函數(shù),拿到 hook 函數(shù)的返回地址之后再通過(guò) on_alloc_memory 函數(shù)來(lái)記錄 原malloc 函數(shù)的返回地址,開辟的大小及 hook 函數(shù)的返回地址。
void on_alloc_memory(void *caller, void *ptr, size_t byte_count) {
    on_acquire_memory(caller, ptr, byte_count, message_type_allocation);
}

// m_memory_messages_containers_ 是上面的 BufferManagement 對(duì)象
static inline void on_acquire_memory(
        void *caller,
        void *ptr,
        size_t byte_count,
        message_type type) {
    // BufferManagement::containers_ 里面有 1<<8 個(gè) BufferQueueContainer 對(duì)象
    // hash ptr 后從 1<<8 拿到其 BufferQueueContainer
    BufferQueueContainer *container = m_memory_messages_containers_.containers_[memory_ptr_hash(
            (uintptr_t) ptr)];
    {
        memory_backtrace_t backtrace{0};
        // 應(yīng)該是 wechat 的 native stack tools 代碼,先不用管
        if (LIKELY(byte_count > 0 && is_stacktrace_enabled && should_do_unwind(byte_count))) {
            size_t frame_size = 0;
            do_unwind(backtrace.frames, MEMHOOK_BACKTRACE_MAX_FRAMES,
                      frame_size);
            backtrace.frame_size = frame_size;
        }
        // 原子操作上鎖 并初始化 BufferQueueContainer(即 container) 中的 queue_ 對(duì)象
        container->lock();
//        inline void lock() {
//            if (UNLIKELY(!mutex_.try_lock())) {
//                g_locker_collision_counter.fetch_add(1, std::memory_order_relaxed);
//                mutex_.lock();
//            }
//
//            if (UNLIKELY(!queue_)) {
//                queue_ = new BufferQueue(SIZE_AUGMENT);//192
//            }
//        }

        auto message = container->queue_->enqueue_allocation_message(type);
//        inline allocation_message_t *enqueue_allocation_message(message_type type) {
//            // 初始化的操作 resize=194 T 是 message_t 類型
//            // void *buffer = realloc(queue_, sizeof(T) * resize);
//            // queue_ = static_cast<T *>(buffer);
            // 從容量為194的容器取出 index 從0開始累加的 message_t
            // 總結(jié) 就是給 index = idx 的 message_t 賦值
//            message_t *msg_idx = &messages_->queue_[messages_->idx_++];// idx 從0開始加
//            msg_idx->type = type; // message_type_allocation
//            msg_idx->index = allocations_->idx_; // 也是從0開始加
//          // 總結(jié) 返回 index = idx 的 allocation_message_t ,準(zhǔn)備給這個(gè)對(duì)象賦值
//            allocation_message_t *buffer = &allocations_->queue_[allocations_->idx_++];
//            *buffer = {};
//            return buffer;
//        }
        if (UNLIKELY(!message)) {
            BufferQueueContainer::g_message_overflow_counter.fetch_add(1,
                                                                       std::memory_order_relaxed);
            CHECK_MESSAGE_OVERFLOW(!message);
        } else {
            // 給上面返回的 allocation_message_t 對(duì)象賦值,有 malloc 函數(shù)的返回地址,開辟的字節(jié)數(shù),malloc 所在函數(shù)的返回地址及 wechat 的一個(gè)棧幀
            message->ptr = reinterpret_cast<uintptr_t>(ptr);
            message->size = byte_count;
            message->caller = reinterpret_cast<uintptr_t>(caller);
            if (backtrace.frame_size) {
                message->backtrace = backtrace;
            }
        }

        container->unlock();

    }
}
  • malloc hook 總結(jié):
      1. 取 BufferManagement::containers_ 容器(size=1<<8) BufferQueueContainer,index 是 ptr 的一種 hash
      1. 初始化 BufferQueueContainer 中的 queue_ = new BufferQueue(SIZE_AUGMENT);//192
        BufferQueue 中有二個(gè)對(duì)象 messages_ 和 allocations_,二個(gè)都是容器(size=194)
      1. &messages_->queue_[messages_->idx_++];取出 queue_ 中 index = idx(該值是自加1的)并賦值
      • 3.1 主要是賦hook的類型( message_type_allocation malloc的類型)和 allocations_ 容器的索引
      1. allocation_message_t *buffer = &allocations_->queue_[allocations_->idx_++];取出 queue_ 中 index = idx(該值是自加1的)并賦值
      • 4.1 主要是malloc 函數(shù)的返回地址,開辟的字節(jié)數(shù),malloc 所在函數(shù)的返回地址及 wechat 的一個(gè)棧幀
  • 2.free hook
    free hook 的代碼宏替換后會(huì)調(diào)到 on_free_memory函數(shù),ptr 是釋放空間的指針
void on_free_memory(void *ptr) {
    on_release_memory(ptr, false);
}

static inline void on_release_memory(void *ptr, bool is_munmap) {

    BufferQueueContainer *container = m_memory_messages_containers_.containers_[memory_ptr_hash(
            (uintptr_t) ptr)];

    container->lock();

    bool ret = container->queue_->enqueue_deletion_message(reinterpret_cast<uintptr_t>(ptr),
                                                           is_munmap);
//      inline bool enqueue_deletion_message(uintptr_t ptr, bool is_munmap) {
//
//            // Fast path. 如果ptr相也就是malloc開辟的空間被free了,messages_->idx_>0
//            if (messages_->idx_ > 0) {
//                message_t *msg_idx = &messages_->queue_[messages_->idx_ - 1];
//                if (((!is_munmap && msg_idx->type == message_type_allocation)
//                     || (is_munmap && msg_idx->type == message_type_mmap))
//                    && allocations_->queue_[msg_idx->index].ptr == ptr) {
//                    msg_idx->type = message_type_nil;
//                    messages_->idx_--;
//                    allocations_->idx_--;
//                    return true;
//                }
//            }
//
//            if (UNLIKELY(!messages_->check_realloc())) {
//                return false;
//            }
//
//            message_t *msg_idx = &messages_->queue_[messages_->idx_++];
//            msg_idx->type = is_munmap ? message_type_munmap : message_type_deletion;
//            msg_idx->ptr = ptr;
//
//            return true;
//        }

    container->unlock();

    if (UNLIKELY(!ret)) {
        BufferQueueContainer::g_message_overflow_counter.fetch_add(1, std::memory_order_relaxed);
        CHECK_MESSAGE_OVERFLOW(!ret);
    }
}
  • free hook 總結(jié)
      1. 取 BufferManagement::containers_ 容器(size=1<<8) BufferQueueContainer,index 是 ptr 的一種 hash
      1. 初始化 BufferQueueContainer 中的 queue_ = new BufferQueue(SIZE_AUGMENT);//192
        BufferQueue 中有二個(gè)對(duì)象 messages_ 和 allocations_,二個(gè)都是容器(size=194)
      1. &messages_->queue_[messages_->idx_++];取出 queue_ 中 index = idx(該值是自加1的)并賦值
      • 3.1 如果((!mmap&&type==malloc)||(mmap&&type=mmap))&&(allocations_->queue_[msg_idx->index].ptr == ptr)的話就刪除之前的 message_t 對(duì)象里面的內(nèi)容,否則執(zhí)行3.2
      • 3.2 主要是賦hook的類型( message_type_deletion delete類型)和 ptr free 的指針

一句話就是 free 的 ptr 是之前記錄的就刪除記錄的內(nèi)容,不是之前的記錄該 free 的 ptr 及 type

3.dump 信息

在 hook 之后,相關(guān)的信息就被記錄到 BufferManagement::containers_中了,而在初始化中又會(huì)將記錄的信息轉(zhuǎn)移到BufferManagement::memory_meta_container_這個(gè)容器中,所以想得到記錄的相關(guān)信息只需要遍歷這個(gè)容器即可。

void dump(bool enable_mmap, const char *log_path, const char *json_path) {
    dump_impl(log_file, json_file, enable_mmap);
    DUMP_RECORD("/sdcard/Android/data/com.tencent.mm/memory-record.dump");
}
static inline void dump_impl(FILE *log_file, FILE *json_file, bool mmap) {

    std::map<void *, caller_meta_t> heap_caller_metas;
    std::map<void *, caller_meta_t> mmap_caller_metas;
    std::map<uint64_t, stack_meta_t> heap_stack_metas;
    std::map<uint64_t, stack_meta_t> mmap_stack_metas;

    // 返回值是 放了多少個(gè)數(shù)據(jù)
    size_t ptr_meta_size = collect_metas(heap_caller_metas,
                                         mmap_caller_metas,
                                         heap_stack_metas,
                                         mmap_stack_metas);

    // 下面就是將上面容器中的數(shù)據(jù)組裝起來(lái)
    cJSON *json_obj = cJSON_CreateObject();
    cJSON *so_native_size_arr = cJSON_AddArrayToObject(json_obj, "SoNativeSize");

    // native heap allocation
    dump_callers(log_file, so_native_size_arr, heap_caller_metas);
    cJSON *native_heap_arr = cJSON_AddArrayToObject(json_obj, "NativeHeap");

    dump_stacks(log_file, native_heap_arr, heap_stack_metas);

    if (mmap) {
        ...
    }
    char *printed = cJSON_PrintUnformatted(json_obj);
    flogger0(json_file, "%s", printed);
    LOGD(TAG, "===> %s", printed);
    cJSON_free(printed);
    cJSON_Delete(json_obj);
}

static inline size_t collect_metas(std::map<void *, caller_meta_t> &heap_caller_metas,
                                   std::map<void *, caller_meta_t> &mmap_caller_metas,
                                   std::map<uint64_t, stack_meta_t> &heap_stack_metas,
                                   std::map<uint64_t, stack_meta_t> &mmap_stack_metas) {
    LOGD(TAG, "collect_metas");

    size_t ptr_meta_size = 0;

    // 由初始化的 memory_hook_init(); 函數(shù),將記錄的 hook 數(shù)據(jù)從 BufferManagement::containers_ 容器轉(zhuǎn)移變化到了 BufferManagement::memory_meta_container_ 里面
    // 也就是 m_memory_meta_container 這個(gè)里面有記錄的 hook 的數(shù)據(jù)
    // 取出了 ptr, &ptr_meta, stack_meta 數(shù)據(jù)
    m_memory_meta_container.for_each( 
            [&](const void *ptr, ptr_meta_t *meta, stack_meta_t *stack_meta) { // 依次取出了 ptr, &ptr_meta, stack_meta 數(shù)據(jù)
                // 區(qū)分 native heap 和 mmap 的 caller 和 stack
                auto &dest_caller_metes =
                        meta->attr.is_mmap ? mmap_caller_metas : heap_caller_metas;
                auto &dest_stack_metas = meta->attr.is_mmap ? mmap_stack_metas : heap_stack_metas;

                void *caller;

                if (stack_meta) {
                    caller = reinterpret_cast<void *>(stack_meta->caller);
                } else {
                    caller = reinterpret_cast<void *>(meta->caller);
                }

                // 向參數(shù)里面的 map 放數(shù)據(jù)
                if (caller) {
                    caller_meta_t &caller_meta = dest_caller_metes[caller];
                    caller_meta.pointers.insert(ptr);
                    caller_meta.total_size += meta->size;
                }
                // 向參數(shù)里面的 map 放數(shù)據(jù)
                if (stack_meta) {

                    auto &dest_stack_meta = dest_stack_metas[(uint64_t) stack_meta];

                    dest_stack_meta.backtrace = stack_meta->backtrace;
                    // 沒(méi)錯(cuò), 這里的確使用 ptr_meta 的 size, 因?yàn)槭窃诒闅v ptr_meta, 因此原來(lái) stack_meta 的 size 僅起引用計(jì)數(shù)作用
                    dest_stack_meta.size += meta->size;
                    dest_stack_meta.caller = stack_meta->caller;
                }

                ptr_meta_size++;
            });

    LOGD(TAG, "collect_metas done");
    return ptr_meta_size; // map 中的個(gè)數(shù)
}

    void for_each(std::function<void(const void *, ptr_meta_t *, stack_meta_t *)> __callback) {
        // 這個(gè)就是初始化中開啟線程轉(zhuǎn)移變化數(shù)據(jù)的目的容器
        for (const auto cw : ptr_meta_containers) { 
            std::lock_guard<std::mutex> container_lock(cw->mutex);
            cw->container.enumerate([&](const void *ptr, ptr_meta_t &ptr_meta) {
                if (ptr_meta.stack_hash) {

                    TARGET_STACK_CONTAINER_LOCKED(stack_meta_container, ptr_meta.stack_hash);
                    // 宏替換后的
//                    stack_container_wrapper_t *stack_meta_container = stack_meta_containers.data()[stack_meta_hash(ptr_meta.stack_hash)];
//                    std::lock_guard<std::mutex> stack_lock(stack_meta_container->mutex)
                    stack_meta_t *stack_meta = nullptr;
                    if (LIKELY(stack_meta_container->container.exist(ptr_meta.stack_hash))) {
                        if (ptr_meta.attr.is_stack_idx) {
                            stack_meta = &stack_meta_container->container.get(ptr_meta.stack_idx);
                        } else {
                            stack_meta = reinterpret_cast<stack_meta_t *>(ptr_meta.ext_stack_ptr);
                        }
                    }
                    __callback(ptr, &ptr_meta, stack_meta); // 回調(diào)到上面那個(gè)函數(shù)
                } else {
                    __callback(ptr, &ptr_meta, nullptr);
                }
            });
        }
    }

至此分析結(jié)束。

祝好
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Lua 5.1 參考手冊(cè) by Roberto Ierusalimschy, Luiz Henrique de F...
    蘇黎九歌閱讀 14,264評(píng)論 0 38
  • 2 內(nèi)存泄漏 2.1 C++中動(dòng)態(tài)內(nèi)存分配引發(fā)問(wèn)題的解決方案 假設(shè)我們要開發(fā)一個(gè)String類,它可以方便地處理字...
    Nrocinu閱讀 247評(píng)論 0 0
  • 1. 語(yǔ)言基礎(chǔ) 1.1 C++的四種類型轉(zhuǎn)換: const_cast => 用于將const變量轉(zhuǎn)為非const;...
    SunnyQjm閱讀 1,307評(píng)論 0 0
  • iOS內(nèi)存問(wèn)題: IBOutlet為啥是weak的?因?yàn)閟ubview添加到view上時(shí),view會(huì)“擁有”sub...
    davidxwwang閱讀 1,631評(píng)論 0 1
  • 一,apk以進(jìn)程的形式運(yùn)行,進(jìn)程的創(chuàng)建是由zygote。 參考文章《深入理解Dalvik虛擬機(jī)- Android應(yīng)...
    Kevin_Junbaozi閱讀 3,191評(píng)論 0 12

友情鏈接更多精彩內(nèi)容