linux 内存占用、内存泄漏

1. slab debug定位kernelspace内存泄露的方法

以下为辅助定位内存泄漏的手段,主要是针对内存kmalloc。

  1. 在kernel中打开如下两个config

  2. 查看meminfo

    如下图,若SUnreclaim一直增加即可初步判断为内核中kmalloc之后没有释放,导致内存泄漏。

  3. slabinfo对比

    开机启动时使用cat /proc/slabinfo备份,出现泄露后再使用cat/proc/slabinfo,将两者进行对比。

  4. 分析上图数据

    图中kmalloc-8192的次数增加较多,在/sys/kernel/slab/kmalloc-8192/alloc_calls中查看调用kmalloc-8192的symbol和他调用的次数,定位到出现泄露的function。


2. kmemleak--Kernel space内存泄露分析工具


2.1. kernel mode的memory申请

SDK里申请kernel mode的memory,主要有两种方式:

  1. vmalloc

    分配大块内存,走budy system;通过cat/proc/vmallocinfo可以统计;

    注:Cat vmallocinfo,如果有buffer块数一直在增加,则是内存泄露。

  2. kmalloc/kmem_cache_create

    分配小于pagesize,走slab机制;通过cat /proc/meminfo里的slab字段可以统计。

    注:如果怀疑有kernel mode内存泄露,运行应用过程中每间隔一段时间cat/proc/meminfo留意slab。如果一直在增加,大概率有内存泄露的可能。具体模块的函数泄露可以用kmemleak debug。


2.2. 检查内存泄漏的方法 -- Kernel Space

Linux kernel 2.6.31后的版本,提供了 KMEMLEAK 的选项,可以拿来测试 kernel modules是否有 memory leakage,用法整理如下。

  1. 修改 .config 设定 KMEMLEAK,重新编译 kernel,重烧 image。

    摘录 .config 如下:

    #
    # Memory Debugging
    #
    CONFIG_HAVE_DEBUG_KMEMLEAK=y
    CONFIG_DEBUG_KMEMLEAK=y
    CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=4096
    
  2. 确认板子上的 kernel 已经提供 kmemleak的功能

    # mount -t debugfs nodev /sys/kernel/debug/
    
    # cat /sys/kernel/debug/kmemleak
    

    注:若存在 kmemleak,表示 kernel 已经支援 kmemleak

  3. 用法举例

    cid:image003.png\\@01D2DB8B.2E89DE10

    注:若沒有手动执行 scan,系统每10分钟自动扫描一次 memory leakage.

  4. 实际测试 Driver memory leakage 的方法

    # mount -t debugfs nodev /sys/kernel/debug/
    # echo clear > /sys/kernel/debug/kmemleak
    # run_your_driver_test_here
    # echo scan > /sys/kernel/debug/kmemleak
    # cat /sys/kernel/debug/kmemleak
    

3. dmalloc--查usr space内存泄露


3.1. 内存泄漏排查

程序运行过程meminfo的Memfree不断减少,echo 3 >/proc/sys/vm/drop_cache也不返回内存,则可能存在内存泄露。

排除kernel space内存泄露后,隔段时间再观察cat /proc/PID/smap每个so的堆,可以找到内存泄漏的so。

准确定位内存泄露需使用dmalloc工具。


3.2. 交叉编译

  1. http://dmalloc.com/可下载dmalloc-5.5.2.gz

    解压,修改configure文件,ac_cv_page_size=0 改为ac_cv_page_size=12

  2. ./configure --prefix=/home/cbm/workplace/dmalloc/output/ --exec-prefix=/home/cbm/workplace/dmalloc/output/CC=arm-buildroot-linux-uclibcgnueabihf-gcc --host=arm-linux CXX=arm-buildroot-linux-uclibcgnueabihf-g++ AR=arm-buildroot-linux-uclibcgnueabihf-ar LD=arm-buildroot-linux-uclibcgnueabihf-ld --enable-threads --enable-shlib

  3. auto脚本对交叉编译支持不够完善,生成的Makefile有少数命令需替换

    ld-G,ar cr需改为$(LD) -G 和 $(AR) cr

  4. make CC=arm-buildroot-linux-uclibcgnueabihf-gcc CXX=arm-buildroot-linux-uclibcgnueabihf-g++ AR=arm-buildroot-linux-uclibcgnueabihf-ar LD=arm-buildroot-linux-uclibcgnueabihf-ld

  5. make install,即可在prefix目录生成bin include和lib。


3.3. 环境变量设置

dmalloc工具进行环境变量设置,如:dmalloc -l /tmp/dmalloc.log all,即输出所有信息并存入dmalloc.log文件;

# dmalloc -l /tmp/dm.log all
DMALLOC_OPTIONS=debug=0xcf4ed2b,log=/tmp/dm.log `
export DMALLOC_OPTIONS `

3.4. 库的应用

  1. 在主代码中添加#include <dmalloc.h>

  2. 更改Makefile,添加CFLAGS += -Iinclude LDFLAGS += -L$(TOP)/dmalloc -ldmalloc

  3. 重新build需要detect的应用


3.5. Leak检测

  1. 通过dmalloc所生产的变量DMALLOC_OPTIONS,手动或自动export到系统中

  2. 执行需detect的应用

  3. 查看变量DMALLOC_OPTIONS中所定义的导出文件内容

  4. 退出需detect的应用

  5. 查看变量DMALLOC_OPTIONS中所定义的导出文件内容

  6. 上述过程所查看的导出文件存在not freed:字串,则为leak点


4. 程序运行内存占用

以公板运行mixer为例,详细说明内存如何分配。


4.1. 实验设备

335+imx307 sensor


4.2. 实验场景

(典型案例)mixer路4路流:JPEG + 主码流 + 子码流 + MD算法


4.3. 实验基础

SDK里kernel space 下ko有两种内存申请方式:

  • vmalloc

    分配大块内存,走budysystem;通过cat/proc/vmallocinfo可以统计;

  • kmalloc/kmem_cache_create

    分配小于pagesize,走slab机制;通过cat/proc/meminfo里的slab字段可以统计。

    内核中常见的还有如alloc_pages/__get_free_page,只能通过free统计,但目前看起来只有emmc会调用。

  • Ioremap

    I/O内存资源的物理地址映射到核心虚地址空间,不占用物理空间;

  • PageTable

    用于将内存的虚拟地址翻译成物理地址,/proc/meminfo中的PageTables统计了Page Table所占用的内存大小。

  • KernelStack

    每一个用户线程都会分配一个kernel stack(内核栈),它是kernel消耗的内存。统计值是/proc/meminfo的KernelStack。

Userspace中常见malloc,小于128K走c标准库的brk,大于128K走mmap,但对于内核来说,一旦发生缺页中断,都是走pageallocater。可以通过procmem工具统计实际占用的物理空间(实际上就是把cat/proc/PID/smap里的RSS/PSS之和)。


4.4. 实验步骤

  1. 开机加载完ko后,drop cache再看cat proc/meminfo和 cat /proc/vmallocinfo

  2. 运行mixer后,drop cache再看cat proc/meminfo、 cat /proc/vmallocinfocat/proc/’PID’/status./procmem PID

  3. 对比工具分析运行前后的vmalloc增加部分


4.5. 总结

free减少 = 16836 – 8888 = 7948K

Vmalloc增加:547page = 2188K

lab增加:6328 – 4792 = 1536K

PageTable+KernelStack增加:536+116 – (352+52) = 248K

应用代码段+ so 代码段 + 栈 + ro段+堆 = 3732K (Pss)

2188 + 1536 + 248 + 3732 = 7704K,Linux kernel并没有统计所有的内存分配,kernel动态分配的内存中有一部分没有计入/proc/meminfo。我们只能大概的统计出来mixer的内存占用。


5. procmem procrank--usr space内存分析工具

源码下载:GitHub - sunao2002002/mem_proc

  1. 解压后用下文内容替换CMakeLists.txt.

    SET(CMAKE_C_COMPILER "arm-buildroot-linux-uclibcgnueabihf-gcc")
    SET(CMAKE_CXX_COMPILER "arm-buildroot-linux-uclibcgnueabihf-g++")
    cmake_minimum_required(VERSION 2.8)
    PROJECT (mem_proc)
    file(GLOB SOURCES "${PROJECT_SOURCE_DIR}/libpagemap/*.c")
    add_definitions (
    -D_LARGEFILE64_SOURCE
    )
    include_directories (${PROJECT_SOURCE_DIR}/libpagemap/include)
    add_library(pagemap ${SOURCES})
    
    add_executable(procmem  ${PROJECT_SOURCE_DIR}/procmem/procmem.c)
    target_link_libraries(procmem pagemap)
    add_executable(procrank  ${PROJECT_SOURCE_DIR}/procrank/procrank.c)
    target_link_libraries(procrank pagemap)
    
  2. cd mem_proc

  3. mkdir out

  4. cd out

  5. cmake ..

  6. make 即可生成procmem和procrank

VSS:Virtual Set Size,虚拟内存耗用内存,包括共享库的内存

RSS:Resident Set Size,实际使用物理内存,包括共享库

PSS:Proportional Set Size,实际使用的物理内存,共享库按比例分配

USS:Unique Set Size,进程独占的物理内存,不计算共享库,也可以理解为将进程杀死能释

https://wx.comake.online/doc/doc/Version_Tiramisu_DLS00V011-20220308/customer/faq/m6-ipc/memory.html

另外可参考
l​​​​​​​ ​​​​​​​https://blog.arstercz.com/what-to-do-when-linux-slab-memory-leak/

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Linux内存占用过高可能是因为程序运行时占用内存过多,或者是由于系统资源的不足。建议使用linux命令top或者free查看系统内存的使用情况,找出占用内存最多的程序,并采取相应的措施优化。 对于Linux内存占用过高的问题,建议采取以下步骤进行排查和优化: 1.使用命令top或者free查看系统内存的使用情况。在终端中输入"top"或者"free -m"命令,可以查看当前系统中各个进程占用内存的情况,以及系统总内存、已用内存和可用内存等信息。 2.找出占用内存最多的进程。在top命令中,按下shift+m可以将进程按照内存占用量从高到低排序。在free命令中,可以查看各个内存区域的使用情况,找出占用内存最多的区域。 3.分析进程或者内存区域的使用情况。根据进程或者内存区域的使用情况,分析其是否存在内存泄漏或者占用过多内存的情况。如果存在问题,需要对相应的程序进行优化。 4.释放不必要的内存。如果存在不必要的内存占用,可以通过释放内存来缓解内存占用过高的问题。在终端中输入"sudo sync && sudo echo 3 > /proc/sys/vm/drop_caches"命令,可以释放系统中的缓存。 5.调整系统内存管理策略。在一些情况下,可能需要调整系统内存管理策略来优化内存的使用效率。例如,可以修改内核参数vm.swappiness的值,来控制系统使用交换分区的频率。 总之,针对Linux内存占用过高的问题,需要通过分析进程或者内存区域的使用情况,以及调整系统内存管理策略等措施,来优化内存的使用效率。 Linux内存占用过高的原因可能有很多,例如程序的内存泄漏、网络应用的频繁使用、多个应用程序同时运行等。最好的办法是检查系统进程并终止不必要的进程,以减少内存占用Linux内存使用率过高可能是因为以下原因: 1. 运行的程序占用了大量内存。可以使用 top 或 htop 等工具查看进程占用内存情况,并尝试关闭不必要的程序或调整它们的配置,以降低它们的内存占用。 2. 内存泄漏。如果程序存在内存泄漏,它们会持续占用系统内存,直到内存耗尽。可以使用 valgrind 等工具来检查程序是否存在内存泄漏,并及时修复。 3. 缓存和缓冲区。Linux 会将一部分内存用于文件缓存和网络缓冲区,以提高系统性能。这些缓存并不会直接占用系统内存,但会在需要时释放。如果系统内存不足,Linux 会自动清理这些缓存,释放内存空间。 4. 内存碎片。当大量进程频繁申请和释放内存时,会产生内存碎片,导致系统无法分配大块的连续内存空间。可以使用内存碎片整理工具(如 malloc_trim)来解决这个问题。 5. 系统参数设置不当。如果系统参数设置不当,可能会导致内存过度使用。可以使用 sysctl 等工具来检查和调整系统参数。 ### 回答2: Linux内存占用过高的原因可能很多,以下是一些常见的原因和解决方法。 1. 内存泄露:程序中存在内存泄露,导致内存占用不断增加。可以使用工具如Valgrind等来检测和调试程序。 2. 进程爆炸:如果系统中有大量的进程存在,每个进程都占用一些内存,就会导致整体内存占用很高。可以使用命令如ps、top等来查看进程情况,并对不必要的进程进行杀掉或优化。 3. 缓存和缓冲区:Linux系统会通过缓存和缓冲区等机制来提升系统的性能,但这些机制也会占用一部分内存。可以通过一些命令如free、vmstat等来查看缓存和缓冲区的情况,并通过调整内核参数来优化。 4. 虚拟内存:如果物理内存不够用,系统会使用虚拟内存进行内存管理,但虚拟内存的实现会带来一定的性能损失。可以通过增加物理内存或调整虚拟内存的相关参数来优化。 5. 软件/服务:很多软件或服务本身就是内存占用较高的,如数据库、Web服务器等。可以通过调整软件或服务的配置来优化内存占用,例如调节缓存大小、减少并发连接数等。 总之,针对Linux内存占用过高的问题,需要综合考虑各种因素,找到合适的解决方法来优化。常用的工具如top、ps、free、vmstat、sar等都可以帮助我们了解系统的内存使用情况。同时,也需要关注系统的物理内存、交换分区、进程数、缓存和虚拟内存等参数,并加以调整和优化。 ### 回答3: Linux内存占用过高可能有多种原因,以下是一些可能的解决方案: 1. 确认是否为缓存导致的内存占用过高。在Linux中,USED的内存不一定是真正占用内存,而有可能是被分配给缓存。可以使用命令“free -m”查看内存占用情况,并注意查看buffers/cache的占用情况。如果buffers/cache的占用比例较高,可以尝试使用“sync && echo 3 > /proc/sys/vm/drop_caches”释放缓存。 2. 关闭不必要的服务。可以使用命令“systemctl list-unit-files”查看所有已安装的服务,并关闭不必要的服务来释放内存。 3. 开启内存垃圾回收机制。如果内存占用过高,可以尝试开启内存垃圾回收机制,将不常用的内存删除以释放内存。 4. 限制进程内存使用。可以使用“ulimit -v”命令限制进程使用的内存大小,避免单个进程占用过多内存。 5. 调整Swap空间。Swap空间可以作为虚拟内存使用,在内存不足时可以将部分数据写入Swap空间。可以调整Swap空间的大小来优化内存使用。 总结:如果Linux内存占用过高,首先需要确认是真正的内存占用还是缓存占用。如果是缓存占用,可以释放缓存;如果是真正的内存占用,可以调整服务、开启内存垃圾回收机制、限制进程内存使用等方式来优化内存使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值