首页 > 系统相关 >Android NDK 内存泄露检测

Android NDK 内存泄露检测

时间:2023-05-07 15:32:06浏览次数:48  
标签:NDK thirdparty .. 内存 env Android out LeakTracer define


 Andorid中Java层代码内存泄露可以借助leakcanary进行检测;

C++上的内存泄露检测库LeakTracer,于是再找了下,找到了Android上的移植版。

首先建立一个项目,在根目录下建立thirdparty目录,进入该目录,

clone相关库代码:

git clone [email protected]:lizhangqu/LeakTracer.git

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

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

//

// 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

#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函数,简单进行内测泄露检测

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到项目根目录

adb pull /sdcard/leaks.out

其内容类似如下内容:

# 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

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

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

Android NDK 内存泄露检测_开发语言

 

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

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的根目录。

之后再次调用命令

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

这时候输出如下

Android NDK 内存泄露检测_#define_02

 

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

MemoryTest *memoryTest = new MemoryTest;

加入delete代码,再跑一次

MemoryTest *memoryTest = new MemoryTest;

delete memoryTest;

输出如下

Android NDK 内存泄露检测_#define_03

 

发现之前的泄露不见了

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

 
 

https://github.com/lizhangqu/NDKMemoryLeakSample

标签:NDK,thirdparty,..,内存,env,Android,out,LeakTracer,define
From: https://blog.51cto.com/u_12389088/6252063

相关文章

  • PCI-5565系列反射内存卡 反射内存交换机
    主要性能:1路发射,一路接收光纤高速网络2.125GHz。最大256个节点。在板128MByteSDRAM。光纤通讯协议不占用CPU资源。动态包长,每个包4到64个字节。33MHzPCI32bit5V和3.3V总线兼容板卡。光纤有效网络带宽50MBytes到170MBytes多模光纤节点距离300M,单模光纤节点距离10KM。4个普......
  • cpp: 内存地址
    在VisualStudio调试器中使用“内存”窗口(C#、C++、VisualBasic、F#)在调试器中查看变量的内存-VisualStudio(Windows)|MicrosoftLearn inta=10; charb; boolc; stringd; cout<<"变量a的地址:"<<&a<<endl; cout<<"变量b的地址:"......
  • C++内存序
    先后一致次序(memory_order_seq_cst)如果程序服从先后一致次序,就简单地把一切事件视为按先后顺序发生,其操作与这种次序保持一致。假设在多线程程序的全部原子类型的实例上,所有的操作都保持先后一致,name它们将按某种特定次序改由单线程执行,则俩个程序的操作毫无区别。缺点:在弱保......
  • 1 - Hand on system programming with Linux - 虚拟内存
    虚拟内存我的博客虚拟内存现代操作系统基于称作虚拟内存的内存模型。这些操作系统包括Linux、UNIX、MSWindows以及macOS。要想真正理解现代操作系统,必须深入理解虚拟内存以及内存管理。没有虚拟内存会有什么问题现在,让我们考虑一个只具有64MBRAM物理内存的情况。在老......
  • 程序的内存空间
    进程的内存空间分布从下往上分别是:正文段(代码段).text只读,可共享;代码段(codesegment/textsegment)通常是指用来存放程序执行代码的一块内存区域。这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读,某些架构也允许代码段为可写,即允许修改程序......
  • 查看linux主机硬件配置:cpu /内存/显卡/磁盘
    CPU总览lscpu查看物理CPU个数cat/proc/cpuinfo|grep"physicalid"|sort|uniq|wc-l查看每个物理CPU中core的个数(即核数)cat/proc/cpuinfo|grep"cpucores"|uniq查看逻辑CPU的个数cat/proc/cpuinfo|grep"processor"|wc-l查看线程数grep'......
  • Android设置语言
    应用语言的切换单纯的切换自身应用的语言。Resourcesresources=getResources();DisplayMetricsdm=resources.getDisplayMetrics();Configurationconfig=resources.getConfiguration();config.setLocale(locale);resources.updateConfiguration(config,dm);......
  • java内存监控工具及命令
    关键字:内存监控工具及命令一篇非常好的内存监控知识,分享给爱学习的亲们.....jinfo:可以输出并修改运行时的java进程的opts。jps:与unix上的ps类似,用来显示本地的java进程,可以查看本地运行着几个java程序,并显示他们的进程号。jstat:一个极强的监视VM......
  • 一统天下 flutter - 存储: shared_preferences - 用于操作 android 的 SharedPreferen
    源码https://github.com/webabcd/flutter_demo作者webabcd一统天下flutter-存储:shared_preferences-用于操作android的SharedPreferences,ios的NSUserDefaults,web的LocalStorage示例如下:lib\storage\shared_preferences.dart/**shared_preferences......
  • AndroidStudio插件GsonFormat快速实现JavaBean
    安装方法一:1.AndroidstudioFile->Settings..->Plugins–>Browserepositores..搜索GsonFormat2.安装插件,重启androidstudio方法二:1.下载GsonFormat.jar;2.AndroidstudioFile->Settings..->Plugins–>installpluginfromdisk..导入下载GsonFormat.jar3.重启android......