admin 管理员组

文章数量: 1184232

内存泄漏的场景

一般内存泄漏主要是slab内存泄漏,ion内存泄漏,私有页面内存泄漏

监控内存泄漏

先利用通用工具初步的排查是否有内存泄漏,首先排查用户态进程

监测用户态进程内存使用情况

watch -n 10 ps -p <PID> -o pid,rss,vsz,comm
watch -n 10 ps -C <进程名> -o pid,rss,vsz,comm

使用ps监控可能泄漏的进程,每10s扫描一遍看看rss,vsz,是否不断增加。

监测内核态内存使用情况

watch -n 10 free -m
               total        used        free      shared  buff/cache   available
内存:      31297        1404        4434          27       25457       29411
交换:       2047         842        1205
  • total:表示系统总的内存容量或交换空间大小,单位通常是 MB。
  • used:指当前已经被使用的内存或交换空间的量。
  • free:是指当前未被使用,可以立即分配给进程使用的内存或交换空间大小。
  • shared:显示的是多个进程共享的内存部分。
  • buff/cache:是系统用于缓存和缓冲的内存空间。
  • available:表示系统当前实际可用于分配给新进程或其他操作的内存量,它考虑了缓存和缓冲等因素对内存的影响,更能反映系统内存的实际可用情况。

监测available是否不断变小,来侧面判断是否有内存泄漏

静态扫描工具,sparse

apt install sparse -y
ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- make C=1 -j8
ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- make C=2 -j8
#make C=1 检查所有重新编译的代码
#make C=2 检查所有代码, 不管是不是被重新编译

用户态内存检测工具1,Valgrind

Valgrind 是一款功能强大且广泛使用的开源工具集,专为调试和分析程序而设计,尤其在检测内存相关问题和性能分析方面表现出色。

apt-get install valgrind -y
cat test.c 
#include <stdio.h>
#include <stdlib.h>

int main() {
    int *ptr = (int *)malloc(sizeof(int));
    // 未释放内存
    return 0;
}

gcc -g -o test test.c
valgrind --leak-check=full ./test
==2676476== Memcheck, a memory error detector
==2676476== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==2676476== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==2676476== Command: ./test
==2676476== 
==2676476== 
==2676476== HEAP SUMMARY:
==2676476==     in use at exit: 4 bytes in 1 blocks
==2676476==   total heap usage: 1 allocs, 0 frees, 4 bytes allocated
==2676476== 
==2676476== 4 bytes in 1 blocks are definitely lost in loss record 1 of 1
==2676476==    at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==2676476==    by 0x10915E: main (test.c:5)
==2676476== 
==2676476== LEAK SUMMARY:
==2676476==    definitely lost: 4 bytes in 1 blocks
==2676476==    indirectly lost: 0 bytes in 0 blocks
==2676476==      possibly lost: 0 bytes in 0 blocks
==2676476==    still reachable: 0 bytes in 0 blocks
==2676476==         suppressed: 0 bytes in 0 blocks
==2676476== 
==2676476== For lists of detected and suppressed errors, rerun with: -s
==2676476== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

报告解读

1. 工具信息

==2676476== Memcheck, a memory error detector
==2676476== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==2676476== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==2676476== Command: ./test

表明使用的是 Valgrind 的 Memcheck 工具进行内存错误检测。
给出了 Valgrind 的版本信息(3.18.1)。
显示被检测的程序命令为 ./test。

2. 堆内存总结

==2676476== HEAP SUMMARY:
==2676476==     in use at exit: 4 bytes in 1 blocks
==2676476==   total heap usage: 1 allocs, 0 frees, 4 bytes allocated

in use at exit:程序结束时,堆上仍有 1 个内存块(1 blocks)未被释放,总共占用 4 字节(4 bytes)。
total heap usage:程序运行期间,总共进行了 1 次内存分配(1 allocs),0 次内存释放(0 frees),累计分配了 4 字节(4 bytes allocated)。

3. 内存泄漏详情

==2676476== 4 bytes in 1 blocks are definitely lost in loss record 1 of 1
==2676476==    at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==2676476==    by 0x10915E: main (my_test.c:5)

definitely lost:明确指出存在 4 字节的内存泄漏,且是在 1 个内存块中。
at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so):显示内存泄漏发生在 malloc 函数调用处。
by 0x10915E: main (my_test.c:5):表明是在 main 函数的 my_test.c 文件的第 5 行调用 malloc 分配内存后,没有释放导致的内存泄漏。

4. 泄漏总结

==2676476== LEAK SUMMARY:
==2676476==    definitely lost: 4 bytes in 1 blocks
==2676476==    indirectly lost: 0 bytes in 0 blocks
==2676476==      possibly lost: 0 bytes in 0 blocks
==2676476==    still reachable: 0 bytes in 0 blocks
==2676476==         suppressed: 0 bytes in 0 blocks

definitely lost:明确丢失的内存,即确定存在内存泄漏的部分。
indirectly lost:间接丢失的内存,通常是由于直接丢失的内存引用了其他内存块导致的。
possibly lost:可能丢失的内存,Valgrind 不能确定是否真的泄漏。
still reachable:仍然可达的内存,程序结束时还能访问到,但没有被释放。
suppressed:被抑制的错误,通常是通过配置文件或选项忽略的错误。

5. 错误总结

==2676476== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

报告显示总共检测到 1 个错误,且没有被抑制的错误。

用户态内存检测工具2,mtrace

  • mtrace 是一个用于检测 C 程序中内存泄漏问题的工具,它通过跟踪 malloc、calloc、realloc 和 free 等内存分配和释放函数的调用情况,帮助你找出未释放的内存块。

1. 包含必要的头文件

在你的 C 代码中,需要包含 <mcheck.h> 头文件,该头文件提供了 mtrace 和 muntrace 函数的声明。

#include <mcheck.h>

2. 启用内存跟踪

在程序的入口处(通常是 main 函数的开头)调用 mtrace 函数来启用内存跟踪功能。mtrace 函数可以接受一个参数,用于指定跟踪日志文件的路径;如果不指定参数,则默认将日志输出到环境变量 MALLOC_TRACE 所指定的文件中。

#include <mcheck.h>
#include <stdio.h>
#include <stdlib.h>

int main() {
    // 启用内存跟踪
    mtrace();

    // 分配内存
    char *ptr = (char *)malloc(100);
    if (ptr == NULL) {
        perror("malloc");
        return 1;
    }
    // 停止内存跟踪,muntrace();可以不使用
    // 这里故意不释放内存,模拟内存泄漏

    return 0;
}

3. 设置跟踪日志文件

在运行程序之前,需要设置 MALLOC_TRACE 环境变量,指定跟踪日志文件的路径。可以在终端中使用 export 命令来设置该环境变量。

export MALLOC_TRACE=./memory_trace.log

4. 编译和运行程序

使用 gcc 编译包含 mtrace 调用的 C 程序。

gcc -g -o my_test my_test.c
./my_test

5. 分析跟踪日志

mtrace my_test  ./memory_trace.log
Memory not freed:
-----------------
   Address     Size     Caller
0x0000000000602010     100  at my_test.c:10

内核态内存检测工具1,kmemleak

开启配置

CONFIG_DEBUG_KERNEL
CONFIG_DEBUG_FS
CONFIG_STACKTRACE
CONFIG_KALLSYMS
CONFIG_CRC32
CONFIG_DEBUG_KMEMLEAK_MEM_POOL_SIZE
CONFIG_DEBUG_KMEMLEAK
CONFIG_DEBUG_KMEMLEAK_AUTO_SCAN

上述配置是开机即开始扫描。如果有内存泄漏可以通过cat /sys/kernel/debug/kmemleak,开机会有如下log

dmesg | grep "kmemleak"
[    9.356806] kmemleak: Kernel memory leak detector initialized (mem pool available: 7452)
[    9.356814] kmemleak: Automatic memory scanning thread started
echo scan > /sys/kernel/debug/kmemleak
cat /sys/kernel/debug/kmemleak
echo off > /sys/kernel/debug/kmemleak

echo scan > /sys/kernel/debug/kmemleak:触发一次扫描
echo clear > /sys/kernel/debug/kmemleak:清除当前 kmemleak 记录的泄露信息
echo off > /sys/kernel/debug/kmemleak:关闭kmemleak(不可逆转的)
echo stack=off > /sys/kernel/debug/kmemleak:关闭task栈扫描
echo stack=on > /sys/kernel/debug/kmemleak:使能task栈扫描
echo scan=on > /sys/kernel/debug/kmemleak:启动自动内存扫描线程
echo scan=off > /sys/kernel/debug/kmemleak:停止自动内存扫描线程
echo scan=<secs> > /sys/kernel/debug/kmemleak:设置自动扫描线程扫描间隔,默认是600,设置0则是停止扫描
echo dump=<addr> > /sys/kernel/debug/kmemleak:dump某个地址的内存块信息,比如上面的echo dump=0xffffffc008efd200 > /sys/kernel/debug/kmemleak即可查看详细信息

内核态内存检测工具2,kasan

kasan配置开启

CONFIG_KASAN

如有内存泄漏或者错误会有log输出

本文标签: 步骤 内存 Kernel