之前分析过在Android Native中分析内存泄漏的方法:Android Native内存泄露检测(针对Android7.0)但是很遗憾这个方法并不适用于Ndk和Jni,因此我们需要为Ndk和Jni寻找一种合适的方法,他就是LeakTracer
这个工具并没有之前libc那么的智能,他需要我们手动的在怀疑的代码段中加入检测代码,原理是将malloc和free函数替换为LeakTracer中带有插桩性质的函数替代,然后在检测前和检测后比较是否内存有成对的申请和释放。适用于C和C++的内存泄漏检测

上代码:
1. LeakTracer源码获取:

https://github.com/zhuyong006/LeakTracer.git

2. 将LeakTracer源码放入Android Studio中cpp的同级目录如下 :

3. 修改CMakeLists.txt文件,如下:

# Sets the minimum version of CMake required to build the native
# library. You should either keep the default value or only pass a
# value of 3.4.0 or lower.cmake_minimum_required(VERSION 3.4.1)# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds it for you.
# Gradle automatically packages shared libraries with your APK.include_directories(src/main/cpp/leak_tracer/include/
)add_library( # Sets the name of the library.leak_tracer# Sets the library as a shared library.STATIC# Provides a relative path to your source file(s).# Associated headers in the same location as their source# file are automatically included.src/main/cpp/leak_tracer/src/AllocationHandlers.cppsrc/main/cpp/leak_tracer/src/MemoryTrace.cpp)add_library( # Sets the name of the library.native-lib# Sets the library as a shared library.SHARED# Provides a relative path to your source file(s).# Associated headers in the same location as their source# file are automatically included.src/main/cpp/native-lib.cpp )# Searches for a specified prebuilt library and stores the path as a
# variable. Because system libraries are included in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.find_library( # Sets the name of the path variable.log-lib# Specifies the name of the NDK library that# you want CMake to locate.log )# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in the
# build script, prebuilt third-party libraries, or system libraries.target_link_libraries( # Specifies the target library.native-libleak_tracer# Links the target library to the log library# included in the NDK.${log-lib} )

这一步的目的是为了将LeakTracer和我们的Native测试代码打到一个动态库中native-lib.so

4. 构建测试程序测试下

  • Java侧代码
package com.sunmi.mmleak;import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.TextView;public class MainActivity extends AppCompatActivity {private int index = 0;private TextView tv = null;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// Example of a call to a native methodtv = (TextView) findViewById(R.id.sample_text);//        new Thread(new Runnable() {//            @Override
//            public void run() {//                do {//                    NativeMmLeak();
//                    index++;
//                    Log.e("Jon","Leak Mem");
//                    try {//                        Thread.sleep(500);
//                    } catch (InterruptedException io) {//
//                    }
//                }while (true);
//            }
//        }).start();NativeMmLeak();}/*** A native method that is implemented by the 'native-lib' native library,* which is packaged with this application.*/public native String NativeMmLeak();// Used to load the 'native-lib' library on application startup.static {System.loadLibrary("native-lib");}
}
  • Native侧代码
#include <jni.h>
#include <string>
#include "leak_tracer/include/MemoryTrace.hpp"
#include <fstream>#ifdef ANDROID#include <android/log.h>#define TAG "Jon"#define ALOGE(fmt, ...) __android_log_print(ANDROID_LOG_ERROR, TAG, fmt, ##__VA_ARGS__)
#define ALOGI(fmt, ...) __android_log_print(ANDROID_LOG_INFO, TAG, fmt, ##__VA_ARGS__)
#define ALOGD(fmt, ...) __android_log_print(ANDROID_LOG_DEBUG, TAG, fmt, ##__VA_ARGS__)
#define ALOGW(fmt, ...) __android_log_print(ANDROID_LOG_WARN, TAG, fmt, ##__VA_ARGS__)
#else
#define ALOGE printf
#define ALOGI printf
#define ALOGD printf
#define ALOGW printf
#endifchar *mm = NULL;
extern "C"
jstring
Java_com_sunmi_mmleak_MainActivity_NativeMmLeak(JNIEnv* env,jobject /* this */) {std::string hello = "Hello from C++";leaktracer::MemoryTrace::GetInstance().startMonitoringAllThreads();mm = (char *)malloc(4096);memset(mm,0x0,4096);leaktracer::MemoryTrace::GetInstance().stopAllMonitoring();std::ofstream out;out.open("/data/leak.out", std::ios_base::out);if (out.is_open()) {leaktracer::MemoryTrace::GetInstance().writeLeaks(out);} else {ALOGE("Failed to write to \"leaks.out\"\n");}return env->NewStringUTF(hello.c_str());
}

这里说明下:

leaktracer::MemoryTrace::GetInstance().startMonitoringAllThreads();

启动内存泄漏检测

leaktracer::MemoryTrace::GetInstance().stopAllMonitoring();

停止内存泄漏检测

leaktracer::MemoryTrace::GetInstance().writeLeaks(out);

将内存泄漏检测的结果写入文件,当前demo中我是写入"/data/leak.out"中的

5. 让我们开始测试吧

  • 首先我们先在data目录下创建一个空文件leak.out
msm8953_64:/data # touch leak.out
touch leak.out
msm8953_64:/data #
  • 打开apk,搜集内存泄漏
    在apk启动后,就会搜集到4K的内存泄漏,然后将堆栈信息写入到/data/leak.out,我们看看都搜集到了什么呢

.# LeakTracer report diff_utc_mono=1658677.590256 leak,
time=9441.017442, stack=0x38282 0x36d20 0x36f72 0x33f8c, size=4096,
data=…

stack就是当前内存泄漏的现场堆栈打印,size就是当前内存泄漏的大小
那么下一步我们就需要还原堆栈了

6. 还原堆栈
LeakTracer有个helpers文件目录:

我们有2种方法都可以还原堆栈现场:leak-analyze-addr2lineleak-analyze-gdb
推荐用leak-analyze-addr2line

root@Jon:/home/jon# leak-analyze-addr2line libnative-lib.so leak.out
Processing "leak.out" log for "libnative-lib.so"
Matching addresses to "libnative-lib.so"
found 1 leak(s)
4096 bytes lost in 1 blocks (one of them allocated at 5687.731067), from following call stack:D:\Project\Android-Samples\MmLeak\app\.externalNativeBuild\cmake\debug\armeabi-v7a/D:/adt-bundle-windows-x86/android-ndk-r18b/sources/cxx-stl/llvm-libc++/include/streambuf:405D:\Project\Android-Samples\MmLeak\app\.externalNativeBuild\cmake\debug\armeabi-v7a/../../../../src/main/cpp/leak_tracer/include/MapMemoryInfo.hpp:187D:\Project\Android-Samples\MmLeak\app\.externalNativeBuild\cmake\debug\armeabi-v7a/D:/adt-bundle-windows-x86/android-ndk-r18b/sources/cxx-stl/llvm-libc++/include/ios:759D:\Project\Android-Samples\MmLeak\app\.externalNativeBuild\cmake\debug\armeabi-v7a/D:\Project\Android-Samples\MmLeak\app\src\main\cpp/native-lib.cpp:32
root@Jon:/home/jon#

如上,非常清晰的告诉我们内存泄漏在native-lib.cpp的32行,正是我们内存泄漏的位置。

再看看leak-analyze-gdb

During symbol reading, Child DIE 0xd4e4 and its abstract origin 0xd2fd have different parents.
During symbol reading, Child DIE 0xd56e and its abstract origin 0x4f85 have different parents.
During symbol reading, Child DIE 0xd555 and its abstract origin 0xd37b have different parents.
During symbol reading, Child DIE 0xd5c6 and its abstract origin 0xd3ae have different parents.
During symbol reading, Child DIE 0xd628 and its abstract origin 0x4dfb have different parents.
During symbol reading, Child DIE 0xd600 and its abstract origin 0xd3ea have different parents.
During symbol reading, Child DIE 0xd72a and its abstract origin 0xc8b8 have different parents.
leaktracer::TMapMemoryInfo<leaktracer::MemoryTrace::_allocation_info_struct>::getNextPair(leaktracer::MemoryTrace::_allocation_info_struct**, void**) + 9 in section .text
0x36d20 is in leaktracer::TMapMemoryInfo<leaktracer::MemoryTrace::_allocation_info_struct>::getNextPair(leaktracer::MemoryTrace::_allocation_info_struct**, void**) (../../../../src/main/cpp/leak_tracer/include/MapMemoryInfo.hpp:187).
187     ../../../../src/main/cpp/leak_tracer/include/MapMemoryInfo.hpp: 没有那个文件或目录.
std::__ndk1::basic_ostream<char, std::__ndk1::char_traits<char> >::operator<<(void const*) + 245 in section .text
0x36f72 is in std::__ndk1::basic_ostream<char, std::__ndk1::char_traits<char> >::operator<<(void const*) (D:/adt-bundle-windows-x86/android-ndk-r18b/sources/cxx-stl/llvm-libc++/include/ios:759).
759     D:/adt-bundle-windows-x86/android-ndk-r18b/sources/cxx-stl/llvm-libc++/include/ios: 没有那个文件或目录.
Java_com_sunmi_mmleak_MainActivity_NativeMmLeak + 111 in section .text
0x33f8c is in Java_com_sunmi_mmleak_MainActivity_NativeMmLeak(JNIEnv*, jobject) (D:\Project\Android-Samples\MmLeak\app\src\main\cpp/native-lib.cpp:32).
32      D:\Project\Android-Samples\MmLeak\app\src\main\cpp/native-lib.cpp: 没有那个文件或目录.

leak-analyze-gdb这个工具显示的信息有些凌乱,不建议使用

最后测试Demo:
https://github.com/zhuyong006/Android-Samples/tree/master/MmLeak

基于Android Ndk/Jni的内存泄漏检测相关推荐

  1. Android 性能优化之内存泄漏检测以及内存优化(上)

    在 Java 中,内存的分配是由程序完成的,而内存的释放则是由 Garbage Collecation(GC) 完成的,Java/Android 程序员不用像 C/C++ 程序员一样手动调用相关函数来 ...

  2. android内存泄漏原因分析,Android Studio3.6的内存泄漏检测功能 VS LeakCanary

    2020年2月,谷歌发布了Android Studio 3.6版.它包括一个新的"内存泄漏检测"功能.这是否意味着我们不再需要流行的内存泄漏检测库"Leak Canary ...

  3. iOS之深入定制基于PLeakSniffer和MLeaksFinder的内存泄漏检测工具

    一.背景 在编写日常业务代码时,或多或少都会引入一些导致内存泄漏的代码,而这种行为又很难被监控,这就导致应用内存泄漏的口子越开越大,直接影响到线上应用的稳定性. 虽然 Xcode 的 Instrucm ...

  4. 基于Android Studio的内存泄漏检测与解决全攻略

    自从Google在2013年发布了Android Studio后,Android Studio凭借着自己良好的内存优化,酷炫的UI主题,强大的自动补全提示以及Gradle的编译支持正逐步取代Eclip ...

  5. 基于Android Studio的Android内存泄漏检测方法

    自从Google在2013年发布了Android Studio后,Android Studio凭借着自己良好的内存优化,酷炫的UI主题,强大的自动补全提示以及Gradle的编译支持正逐步取代Eclip ...

  6. Android内存泄漏检测工具使用手册

    Android内存泄漏检测工具使用手册 前言 LeakCanary 在Android中接入LeakCanary LeakCanary内存泄漏分析 内存泄漏上报到服务端 Shark Shark分析当前应 ...

  7. Android 内存泄漏检测开源库LeakCanary 研究

    1. Android 内存空间不足会引发的问题 1.1 异常 1.2 卡顿 1.3 从 Java 堆内存超限这个问题开始 2. 内存优化着手点 2.1 检测 RAM usage 2.2 进程 2.3 ...

  8. Android系统性能优化(67)----内存泄漏检测

    Android内存泄漏检测 一.      背景 内存泄漏(Memory Leak)是指程序中己动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等 ...

  9. 插桩valgrind_基于动态插桩的CC++内存泄漏检测工具的设计与实现.pdf

    基于动态插桩的CC++内存泄漏检测工具的设计与实现.pdf 第32卷第6期 计 算 机 应 用 研 究 V01.32No.6 20l5年 6月 ApplicationResearchofCompute ...

  10. Android内存泄漏检测及修复(转载)

    本文转载自:Android内存泄漏检测及修复 最近在查Android系统上的一个内存泄漏的问题,发现利用Android ADT带的DDMS的Heap功能很好用(需要系统默认开放权限较高才行,否则DDM ...

最新文章

  1. wake_lock_timeout的使用方法【转】
  2. 对于未来的多种可能,这几位中国科学家想说
  3. 重走丝绸之路:海尔如何探索全球生活智慧?
  4. TCP/IP的四元组 五元组 七元组
  5. python知识:函数abs、delattr、hash、memeryview、index
  6. linux 7 没有权限访问,技术|RHCSA 系列(十三): 在 RHEL 7 中使用 SELinux 进行强制访问控制...
  7. android自动跑马灯,Android-最强跑马灯
  8. 【Java】基于Socket的C/S聊天程序
  9. 设计模式之组合模式(Composite Pattern)
  10. php 405,php Restler 405 Method Not Allowed 问题解决啦,restlerallowed_PHP教程
  11. 一个傻瓜式构建可视化 web的 Python 神器 -- streamlit 教程
  12. 208个地级市城市和农村总收入、可支配收入面板数据(2010-2019年)
  13. 如何图片格式批量转换?
  14. 统计局:1月份中国制造业采购经理指数为49.5%
  15. 常用的加密方式有哪些?
  16. 统计基础之差异性归一化正态分布
  17. unsupported format character '}' (0x7d) at index 83
  18. 游戏服务器框架概括分析
  19. 2021-08-03 Linux题目整理
  20. 第12周项目2—摩托车继承自行车和机动车

热门文章

  1. 【Struts1】--beanutils
  2. 运行Myeclipse时,如何删除IVM窗口
  3. web项目开发的基本流程
  4. .NET中栈和堆的比较
  5. C#两种创建快捷方式的方法
  6. 电脑锁屏按什么键解锁_锁屏键除了锁屏还能干什么?这 6 个 App 带你玩转手机实体键...
  7. 设计模式学习与应用——单例模式
  8. Android爬坑之旅之FileProvider(Failed to find configured root that contains)
  9. hibernate笔记--组合主键映射方法
  10. 轻松搞定RabbitMQ(四)——发布/订阅