前言

最近写C++代码,老是担心代码存在内存泄露,胆战心惊的,Andorid中Java层代码内存泄露可以借助leakcanary进行检测;找了一番,找到了PC上C++上的内存泄露检测库LeakTracer,于是再找了下,找到了Android上的移植版。

首先建立一个项目,在根目录下建立thirdparty目录,进入该目录,clone相关库代码

1
git clone git@github.com:lizhangqu/LeakTracer.git

在项目src/main/cpp下建立CMakeLists.txt,内容如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
project(Test)
cmake_minimum_required (VERSION 3.6)
include_directories(
${PROJECT_SOURCE_DIR}/include/
${PROJECT_SOURCE_DIR}/../../../../thirdparty/LeakTracer/libleaktracer/include/
)
set(LEAKTRACER_SOURCES
${PROJECT_SOURCE_DIR}/../../../../thirdparty/LeakTracer/libleaktracer/src/AllocationHandlers.cpp
#${PROJECT_SOURCE_DIR}/../../../../thirdparty/LeakTracer/libleaktracer/src/LeakTracerC.c
#检测c代码时打开此注释,否则不要打开
${PROJECT_SOURCE_DIR}/../../../../thirdparty/LeakTracer/libleaktracer/src/MemoryTrace.cpp
)
add_library(leaktracer STATIC ${LEAKTRACER_SOURCES})
set(TEST_FILES
${CMAKE_SOURCE_DIR}/native.cpp
)
add_library(
test-jni
SHARED
${TEST_FILES})
target_link_libraries(
test-jni
leaktracer
log
)

建立src/main/cpp/include/native.h和src/main/cpp/native.cpp文件

native.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
//
// Created by 李樟取 on 2017/6/4.
//
#ifndef TEST_H
#define TEST_H
#include "jni.h"
#ifndef NELEM
# define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
#endif
#ifndef CLASSNAME
#define CLASSNAME "io/github/lizhangqu/test/Test"
#endif
#ifdef ANDROID
#include <android/log.h>
#define TAG "Test"
#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
#endif
#endif //TEST_H

native.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include "native.h"
#include "MemoryTrace.hpp"
#include <fstream>
void test(JNIEnv *env, jobject thiz) {
}
static const JNINativeMethod sMethods[] = {
{
const_cast<char *>("test"),
const_cast<char *>("()V"),
reinterpret_cast<void *>(test)
},
};
int registerNativeMethods(JNIEnv *env, const char *className, const JNINativeMethod *methods,
const int numMethods) {
jclass clazz = env->FindClass(className);
if (!clazz) {
ALOGE("Native registration unable to find class '%s'\n", className);
return JNI_FALSE;
}
if (env->RegisterNatives(clazz, methods, numMethods) != 0) {
ALOGE("RegisterNatives failed for '%s'\n", className);
env->DeleteLocalRef(clazz);
return JNI_FALSE;
}
env->DeleteLocalRef(clazz);
return JNI_TRUE;
}
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
JNIEnv *env;
if (vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6) != JNI_OK) {
return -1;
}
registerNativeMethods(env, CLASSNAME, sMethods, NELEM(sMethods));
return JNI_VERSION_1_6;
}

编写test函数,简单进行内测泄露检测

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class MemoryTest {
};
void test(JNIEnv *env, jobject thiz) {
leaktracer::MemoryTrace::GetInstance().startMonitoringAllThreads();
MemoryTest *memoryTest = new MemoryTest;
leaktracer::MemoryTrace::GetInstance().stopAllMonitoring();
std::ofstream out;
out.open("/sdcard/leaks.out", std::ios_base::out);
if (out.is_open()) {
leaktracer::MemoryTrace::GetInstance().writeLeaks(out);
} else {
ALOGE("Failed to write to \"leaks.out\"\n");
}
}

运行程序后调用test函数,将/sdcard/leaks.out pull到项目根目录

1
adb pull /sdcard/leaks.out

其内容类似如下内容

1
2
# LeakTracer report diff_utc_mono=1496511718.682943
leak, time=135120.534718, stack=0x36fd6 0x35a90 0x359a4 0x32fea 0xc952d3d0, size=1, data=�

借助thirdparty/LeakTracer/helper/leak-analyze-addr2line工具还原内测泄露堆栈。

进入项目根目录,执行leak-analyze-addr2line

1
./thirdparty/LeakTracer/helpers/leak-analyze-addr2line ./library/build/intermediates/cmake/debug/obj/armeabi/libtest-jni.so ./leaks.out

在mac上,会出现一个错误,原因是leak-analyze-addr2line中用到了addr2line工具,而mac上如果没有此工具,就会报错,错误如下:

解决方法很简单,将ndk目录中的arm-linux-androideabi-addr2line拷到./thirdparty/LeakTracer/helpers/下,并重命名为addr2line,然后将./thirdparty/LeakTracer/helpers/加到环境变量中,如下代码

1
2
cp $ANDROID_NDK_HOME/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-addr2line ./thirdparty/LeakTracer/helpers/addr2line
export PATH=$PATH:`pwd`/thirdparty/LeakTracer/helpers

$ANDROID_NDK_HOME表示ndk的根目录。

之后再次调用命令

1
./thirdparty/LeakTracer/helpers/leak-analyze-addr2line ./library/build/intermediates/cmake/debug/obj/armeabi/libtest-jni.so ./leaks.out

这时候输出如下

native.cpp:15行出现泄露,找到15行对应的代码,即如下代码出现泄露

1
MemoryTest *memoryTest = new MemoryTest;

加入delete代码,再跑一次

1
2
MemoryTest *memoryTest = new MemoryTest;
delete memoryTest;

输出如下

发现之前的泄露不见了

最后,值得注意的是,要想使用LeakTracer需要保留so足够多的debug信息,否则可能不能正常检测。

项目Demo地址见NDKMemoryLeakSample

http://fucknmb.com/2017/06/05/Android-NDK-%E5%86%85%E5%AD%98%E6%B3%84%E9%9C%B2%E6%A3%80%E6%B5%8B/

Android NDK 内存泄露检测相关推荐

  1. android native堆内存泄露,Android Native内存泄露检测

    Android Studio没有提供直接的Native层的内存泄露检测工具,但我们仍可以通过开源工具进行动态检测和静态检测 动态检测 在APP运行时进行检测,就像LeakCanary Update: ...

  2. 【Android】内存泄露 使用 LeakCanary 应当如何应对?最全的解决

    目录 1.LeakCanary简介 2.入手指南 3.基础使用 3.1介绍 3.1.1什么是内存泄漏 3.1.2内存泄漏的常见原因 3.1.3为什么我应该使用LeakCanary 3.2.LeakCa ...

  3. C语言内存泄露检测--Memwatch

    项目:迅雷下载库内存泄露检测 作者:曾金龙 供职:深圳迅雷网络技术股份有限公司 领域:迅雷下载库 时间:2014-07-26 迅雷的移动下载库是用C语言编写的,为了能够横跨欧亚非拉(ios,andro ...

  4. Ubuntu下内存泄露检测工具Valgrind的使用

    在VS中可以用VLD检测是否有内存泄露,可以参考http://blog.csdn.net/fengbingchun/article/details/44195959,下面介绍下Ubuntu中内存泄露检 ...

  5. memwatch内存泄露检测工具

    工具介绍 官网 http://www.linkdata.se/sourcecode/memwatch/ 其功能如下官网介绍,挑选重点整理: 1. 号称功能: 内存泄露检测 (检测未释放内存, 即 动态 ...

  6. DevPartner Studio Professional Edition 11 内存泄露检测使用

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! DevP ...

  7. UE3 MemLeakCheck Tracking(内存泄露检测追踪)

    MemLeakCheck Tracking(内存泄露检测追踪) 概述 运行 MemLeakCheck MemLeakCheck MemLeakCheck -fast Release vs. Test ...

  8. 转载浅谈MFC内存泄露检测及内存越界访问保护机制

    2019独角兽企业重金招聘Python工程师标准>>> 本文所有代码均在VC2008下编译.调试.如果您使用的编译器不同,结果可能会有差别,但本文讲述的原理对于大部分编译器应该是相似 ...

  9. 精准 iOS 内存泄露检测工具

    MLeaksFinder:精准 iOS 内存泄露检测工具 发表于 2016-02-22   |   zepo   |   23 Comments 背景 平常我们都会用 Instrument 的 Lea ...

最新文章

  1. OPatch cannot find a valid oraInst.loc file to locate Central Inventory
  2. 使用结构体的形式使一个函数返回多个数据
  3. oracle 事务测试
  4. linux之vim复制多行、光标跳转到指定行、插入当前光标上和下行
  5. 在gitee上创建自己的仓库步骤
  6. 吃鱼可以不挑刺了?华中农业大学发现鳊鱼肌间刺表达基因,可培育“无刺鱼”...
  7. AxureRP9不同Page使用同一个Master,触发不同事件。
  8. 类间关系有很多种 UML
  9. java 4种跟踪会话技术_会话跟踪技术
  10. CentOS 7 安装及设置
  11. django 获取 axios get 过来的数据_一起DevOps系列12django数据库创建与使用
  12. 内容分发系统MediaEW:助新闻媒体转投HTML5
  13. c++ mysql 写库 乱码 ??_mysql c++ 乱码 解决方法
  14. formData上传音乐文件
  15. python中的main函数
  16. Pinterest和Instagram哪个更好用?姐妹还是天敌...
  17. JAVA中分号用中文还是英文_【英文中有分号(;)吗?怎么用呢?】作业帮
  18. 【JavaScript 逆向】webpack 之某妹游戏登录逆向
  19. 10条网站易用性技巧
  20. RuntimeError: Distributed package doesn‘t have NCCL built in

热门文章

  1. 洛谷 U5122 T2-power of 2(费马小定理)
  2. 【BZOJ-1458】士兵占领 最大流
  3. 《Android编程权威指南》-读书笔记(七) -处理旋转设备
  4. 吴恩达 coursera ML 第十三课总结+作业答案
  5. Python学习笔记:‘’AttributeError: NoneType object has no attribute‘’
  6. 类的初始化(构造函数)
  7. linux环境切换python3版本
  8. 二十万字C/C++、嵌入式软开面试题全集宝典六
  9. 判断一个字符串是否是数值
  10. 【算法】ROI Align 原理