15.优化 - memory hook(matrix malloc hook)

  Matrix 中的 memory hook 也是基于 xhook 的实现的,可以记录 malloc、calloc、free、mmap 等函数的调用。

1.初始化

  初始化主要做了二件事,一是 hook 函数的调用,二是开启了一个 while(true) 线程将记录的数据由一组容器转移变换到另一组容器中。

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 函数调用
            hook(regex);
            env->ReleaseStringUTFChars(jregex, regex);
        }
    }
    ...
    xhook_grouped_ignore(HOOK_REQUEST_GROUPID_MEMORY, ".*/libandroid_runtime\\.so$", nullptr);
    xhook_unblock_refresh();
}
  • hook 函数调用
static void hook(const char *regex) { // regex 是 hook 哪个 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 的函数有如下
// 与开辟、释放空间相关的
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 相关的
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
};

// 转换前
int ret = xhook_grouped_register(HOOK_REQUEST_GROUPID_MEMORY, regex, f.name, f.handler_ptr, f.origin_ptr);
// 实际 hook
int ret = xhook_grouped_register(HOOK_REQUEST_GROUPID_MEMORY, ".*library-not-exists\\.so$",malloc, (void *) h_malloc, NULL);

而实际调用的 h_malloc 函数也需要进行一点点转化才可以得到

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;
}
// 将上面的代码进行宏替换后得到
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;
}

当调用相关 hook 函数后,先通过 dlopen 打开 libc.so ,在拿到 libc.so 里面的 malloc 原函数,先调用原函数,拿到 hook 函数的返回地址之后再通过 on_alloc_memory 函数来记录 原malloc 函数的返回地址,开辟的大小及 hook 函数的返回地址。

  • 开启一个线程,memory_hook_init
// memory_meta_container 构造函数 舒适化了 ptr_meta_containers、stack_meta_containers 这二个容器
static memory_meta_container m_memory_meta_container;
//    memory_meta_container() {
//        size_t cap = ptr_meta_capacity();// 1
//        ptr_meta_containers.reserve(cap);// 申请n个元素的内存空间
//        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 构造函数中将容器 containers_ 初始化并添加了 1<<8 个 BufferQueueContainer() 对象
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;
//    }

// 调用的是这里
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_);
    }

    // 数据由 BufferManagement::containers_ 容器转移变化到了 BufferManagement::memory_meta_container_ 里面
    // 而 BufferManagement::memory_meta_container_ 是个静态对象
    [[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 个对象
                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_ 并将原来的值清空
                        HOOK_LOG_ERROR("Swap queue ... ");
                        // 将数据赋值给 swapped,并且把 container 里面的数据置空
                        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 内的 messages_ 和 allocations_ 容器 里面的内容
                            [&](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);
                                    }
                                    // 一个 static obj
                                    // 有一样的 native stack 的话就放在一个类似与链表的地方,没有的话就新建一个  像 HashMap<String,LinkArray>?
                                    // 返回插入的 ptr 和 stack 对象给这边add数据,对饮之前的 messages_ 和 allocation_message_t 对象
                                    // memory_meta_container_ 是一个静态变量
                                    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) {  // 回调填充数据
                                                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;
                }
            }
        }
    }

总结:将数据由 BufferManagement::containers_ 容器转移到了 BufferManagement::memory_meta_container_ 里面。

2.hook 记录相关信息

  分析 malloc 及 free 这二个函数 hook 之后记录的信息。

  • 1.malloc hook
      在初始化中提到 malloc 的 hook 函数是 h_malloc,而该函数通过 dlopen 打开 libc.so ,在拿到 libc.so 里面的 malloc 原函数,先调用原函数,拿到 hook 函数的返回地址之后再通过 on_alloc_memory 函数来记录 原malloc 函数的返回地址,开辟的大小及 hook 函数的返回地址。
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 对象
static inline void on_acquire_memory(
        void *caller,
        void *ptr,
        size_t byte_count,
        message_type type) {
    // BufferManagement::containers_ 里面有 1<<8 个 BufferQueueContainer 对象
    // hash ptr 后从 1<<8 拿到其 BufferQueueContainer
    BufferQueueContainer *container = m_memory_messages_containers_.containers_[memory_ptr_hash(
            (uintptr_t) ptr)];
    {
        memory_backtrace_t backtrace{0};
        // 应该是 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_ 对象
        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
            // 总结 就是给 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开始加
//          // 总结 返回 index = idx 的 allocation_message_t ,准备给这个对象赋值
//            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 对象赋值,有 malloc 函数的返回地址,开辟的字节数,malloc 所在函数的返回地址及 wechat 的一个栈帧
            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 总结:
      1. 取 BufferManagement::containers_ 容器(size=1<<8) BufferQueueContainer,index 是 ptr 的一种 hash
      1. 初始化 BufferQueueContainer 中的 queue_ = new BufferQueue(SIZE_AUGMENT);//192
        BufferQueue 中有二个对象 messages_ 和 allocations_,二个都是容器(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 函数的返回地址,开辟的字节数,malloc 所在函数的返回地址及 wechat 的一个栈帧
  • 2.free hook
    free hook 的代码宏替换后会调到 on_free_memory函数,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 总结
      1. 取 BufferManagement::containers_ 容器(size=1<<8) BufferQueueContainer,index 是 ptr 的一种 hash
      1. 初始化 BufferQueueContainer 中的 queue_ = new BufferQueue(SIZE_AUGMENT);//192
        BufferQueue 中有二个对象 messages_ 和 allocations_,二个都是容器(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 对象里面的内容,否则执行3.2
      • 3.2 主要是赋hook的类型( message_type_deletion delete类型)和 ptr free 的指针

一句话就是 free 的 ptr 是之前记录的就删除记录的内容,不是之前的记录该 free 的 ptr 及 type

3.dump 信息

在 hook 之后,相关的信息就被记录到 BufferManagement::containers_中了,而在初始化中又会将记录的信息转移到BufferManagement::memory_meta_container_这个容器中,所以想得到记录的相关信息只需要遍历这个容器即可。

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;

    // 返回值是 放了多少个数据
    size_t ptr_meta_size = collect_metas(heap_caller_metas,
                                         mmap_caller_metas,
                                         heap_stack_metas,
                                         mmap_stack_metas);

    // 下面就是将上面容器中的数据组装起来
    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(); 函数,将记录的 hook 数据从 BufferManagement::containers_ 容器转移变化到了 BufferManagement::memory_meta_container_ 里面
    // 也就是 m_memory_meta_container 这个里面有记录的 hook 的数据
    // 取出了 ptr, &ptr_meta, stack_meta 数据
    m_memory_meta_container.for_each( 
            [&](const void *ptr, ptr_meta_t *meta, stack_meta_t *stack_meta) { // 依次取出了 ptr, &ptr_meta, stack_meta 数据
                // 区分 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);
                }

                // 向参数里面的 map 放数据
                if (caller) {
                    caller_meta_t &caller_meta = dest_caller_metes[caller];
                    caller_meta.pointers.insert(ptr);
                    caller_meta.total_size += meta->size;
                }
                // 向参数里面的 map 放数据
                if (stack_meta) {

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

                    dest_stack_meta.backtrace = stack_meta->backtrace;
                    // 没错, 这里的确使用 ptr_meta 的 size, 因为是在遍历 ptr_meta, 因此原来 stack_meta 的 size 仅起引用计数作用
                    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 中的个数
}

    void for_each(std::function<void(const void *, ptr_meta_t *, stack_meta_t *)> __callback) {
        // 这个就是初始化中开启线程转移变化数据的目的容器
        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); // 回调到上面那个函数
                } else {
                    __callback(ptr, &ptr_meta, nullptr);
                }
            });
        }
    }

至此分析结束。

祝好
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容

  • Lua 5.1 参考手册 by Roberto Ierusalimschy, Luiz Henrique de F...
    苏黎九歌阅读 13,766评论 0 38
  • 2 内存泄漏 2.1 C++中动态内存分配引发问题的解决方案 假设我们要开发一个String类,它可以方便地处理字...
    Nrocinu阅读 197评论 0 0
  • 1. 语言基础 1.1 C++的四种类型转换: const_cast => 用于将const变量转为非const;...
    SunnyQjm阅读 1,134评论 0 0
  • iOS内存问题: IBOutlet为啥是weak的?因为subview添加到view上时,view会“拥有”sub...
    davidxwwang阅读 1,534评论 0 1
  • 一,apk以进程的形式运行,进程的创建是由zygote。 参考文章《深入理解Dalvik虚拟机- Android应...
    Kevin_Junbaozi阅读 2,833评论 0 12