关键词:sqllite、meminfo、slabinfo、alloc_calls、nand、SUnreclaim等等。

下面记录一个由于驱动导致的内存泄漏问题分析过程。

首先介绍问题背景,在一款嵌入式设备上,新使用sqllite库进行数据库操作,在操作数据(大量读写操作)一段时间之后,发生OOM现象。

然后OOM会选择进程kill,即使系统中不剩什么进程,仍然内存紧张。

下面就介绍从上往下查找问题,然后在底层掐住RootCause,进而解决问题的分析过程。

1. 问题初步分析

首先怀疑的是sqllite库问题,在PC进行同样的测试未发现内存泄漏。在另一款参考设备上,进行同样的测试,未发现内存泄漏。

以上测试确保了测试程序、sqllite库等一致,仅交叉工具链和平台不一致。

结论:可以基本肯定sqllite库以及测试程序没有问题,可能的问题包括交叉工具链、平台问题。平台问题更大,所以问题集中到具体平台上进行分析。

疑问点:

1. 为何进程退出后,泄漏的内存没有释放?参见分析,是因为SUnreclaim的slab内存不在进程内存统计范围之内。

2. 是否由于工具链不同导致库函数表现不一致?参见分析1,内存泄漏点在内核驱动中。 参见分析2,经过在RAM上运行sqllite测试;单独测试NAND文件系统,得出泄漏和sqllite无关。

3. 是平台内核导致的泄漏吗?参见分析,确定泄漏在kmalloc-4096这个slab中。

2. 具体平台查找内存泄漏方向

定位内存泄漏按照从大到小的思路,即首先看系统内存哪里泄漏,然后再看进程内存哪里泄漏,最后看哪种内存泄漏。

2.1 分析系统内存

首先通过cat /proc/meminfo,然后分析泄漏点。

从MemFree和MemAvailable看,内存将低了235M和228M。

然后看一下下面内存消耗在哪里?可以看出slab消耗了228M,再细节可以看出SUreclaim消耗了228M。基本确定

结论:确定由于Unreclaim类型的slab泄漏导致的内存泄漏。

疑问点:找出具体哪个slab泄漏了?参见分析,在kmalloc-4096这个slab中。 哪个调用的slab申请?参见分析,通过kmalloc-4096的alloc_calls可以知道调用点。

2.2 分析进程内存

通过pmap -X -p `pidof xxx`来获取进程的地址映射空间,可以分析进程内存细节。

结论:通过下面的对比,可以看出进程本身没有导致内存泄漏。所以内存泄漏虽然有此进程导致,但是泄漏点不在进程中。

2.3 分析slab内存泄漏点

既然确定slab导致的泄漏,那么就需要使用slabtop、/proc/slabinfo以及/sys/kernel/slab来分析。

从下面可以看出泄漏点在kmalloc-4096这个slab,这个slab消耗的内存为250M左右。

然后就是去找slab的调用记录,幸运的是系统在/sys/kernel/slab/*/中提供了alloc_calls和free_calls。

alloc_calls:

1 pidmap_init+0x4e/0x10c age=418000 pid=0

1 con_init+0xf6/0x21c age=418007 pid=0

1 pcpu_mem_zalloc+0x36/0x74 age=417641 pid=1

1 seq_buf_alloc+0x26/0x54 age=0 pid=349

1 register_leaf_sysctl_tables+0x74/0x1b0 age=418000 pid=0

1 ubifs_mount+0x68/0x15e8 age=416589 pid=1

1 ubifs_mount+0xdaa/0x15e8 age=416588 pid=1

1 nand_scan_tail+0xa2/0x6a8 age=417469 pid=1

1 ubi_attach_mtd_dev+0x9a/0xc38 age=417168 pid=1

1 sourcesink_bind+0x382/0x4c0 age=417588 pid=1

1 vid_dev_probe+0x32/0x1a0 age=417569 pid=1

2 hantrodec_probe+0x56/0x944 age=417502/417512/417523 pid=1

55898 spinand_cmdfunc+0x236/0x52c age=8997/225988/416514 pid=1-202 1 flow_cache_cpu_prepare.isra.7+0x3c/0x74 age=417889 pid=1

free_calls:

55840 age=343019 pid=0

59 kvfree+0x2a/0x60 age=0/239003/415431 pid=140-349

1 ubifs_read_superblock+0x690/0xe14 age=416600 pid=1

8 kobject_uevent_env+0xda/0x580 age=416605/417396/417653 pid=1

3 uevent_show+0x5e/0xf4 age=409638/411302/413798 pid=143-150

1 skb_free_head+0x2c/0x6c age=417902 pid=1

结论:从alloc_calls可以看出spinand_cmdfunc中申请了55898次slab,和系统内存泄漏量基本一致。

2.4 分析驱动内存泄漏

通过objdump -S -l -D vmlinux > vmlinux.txt,然后结合反汇编代码,找到spinand_cmdfunc+0x236可以找到具体点。

805829e2: e3f26433 bsr 0x803cf248 //803cf248 <_end>

805829e6: c4004820 lsli r0, r0, 0spinand_cmdfunc():/home/al/deepeye1000/linux/drivers/staging/mt29f_spinand/mt29f_spinand.c:806spinand_program_page(info->spi, state->row, state->col,

所以问题最终指向了mt29f_spinand.c的806行,spinand_program_page()这个函数里面。

分析此驱动代码,可以看出通过devm_kzalloc()申请的内存没有被释放的点。虽然此内存在模块卸载的时候会被自动释放,但是NAND驱动一般不会被卸载。

结论:确定泄漏点在spinand_program_page()中。

3. 旁证测试

基本上找到的问题点,为了验证上述分析做了几个简单的测试。

3.1 在ramfs中进行sqllite数据库操作

既然泄漏点在NAND驱动中,那么避开在NAND中进行读写操作即可。在/tmp目录下,进行数据库操作,作为对比测试。

同样的软件和平台下,运行同样的业务。

结论:在ramfs中进行操作,没有发生内存泄漏。说明泄漏sqllite操作无关。。

3.2 在NAND上进行文件cp、rm等操作

既然泄漏点在NAND,那么不使用数据库读写,纯文件系统读写如何呢?

经过测试,同样发现SUreclaim内存增加导致的泄漏。

结论:内存泄漏跟NAND上文件操作有关。

为什么之前没有发现内存泄漏问题呢?原来主要业务是运行应用,很少对NAND进行写,即使有写也是偶尔的,发现不了内存泄漏。这种情况在频繁的读写、删除操作下比较容易复现。

4. 解决问题

解决的思路就是确保在函数退出的时候,保证wbuf的内存能够得到释放。

diff--git a/drivers/staging/mt29f_spinand/mt29f_spinand.c b/drivers/staging/mt29f_spinand/mt29f_spinand.c

index 2474d88..7042934 100644

--- a/drivers/staging/mt29f_spinand/mt29f_spinand.c+++ b/drivers/staging/mt29f_spinand/mt29f_spinand.c

@@-495,7 +495,8 @@ static int spinand_program_page(struct spi_device *spi_nand,

#ifdef CONFIG_MTD_SPINAND_ONDIEECC

unsignedinti, j;- wbuf = devm_kzalloc(&spi_nand->dev, CACHE_BUF, GFP_KERNEL);

+ wbuf = kzalloc(CACHE_BUF, GFP_KERNEL);if (!wbuf)return -ENOMEM;

@@-509,7 +510,7 @@ static int spinand_program_page(struct spi_device *spi_nand,

retval=spinand_enable_ecc(spi_nand);if (retval < 0) {

dev_err(&spi_nand->dev, "enable ecc failed!!");- return retval;

+ gotoexit;

}

}#else...

-

- return 0;

+exit:

+#ifdef CONFIG_MTD_SPINAND_ONDIEECC

+ kfree(wbuf);

+#endif

+ returnretval;

}

5. 验证测试

基于以上的分析过程,构建测试用例:

1. 进行同样的NAND上sqllite数据操作

2. 同样重复cp、rm操作NAND上文件系统

linux pmap 内存泄露,一个驱动导致的内存泄漏问题的分析过程(meminfo-pmap-slabtop-alloc_calls)...相关推荐

  1. matlab版本越高越吃内存,解决显卡驱动导致的内存占用越来越高的问题

    假期里有空的时候用电脑给孩子放点动画片之类的视频看,最初使用的是pps,结果发现一开始很流畅,看着看着就越来越卡,一看内存,几乎100%了,怀疑是pps版本问题,更换最新版.较老版本都是如此,后来用终 ...

  2. iPhone开发资料之内存管理 ,循环引用导致的内存问题

    iPhone开发资料之内存管理 ,循环引用导致的内存问题 https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual ...

  3. c++内存泄露:使用性能监视器进行内存泄露的确认

    对于服务器程序,在不停的运作中,如何去测试是否存在内存泄露,如果你的开发环境是在windows下,那么我们就可以使用windows自带的性能监视器来观察程序的性能. 使用此例子: // Test.c ...

  4. WPF内存泄露:CollectionViewSource.GetDefaultView导致Cache对象

    在使用OpenExpressApp进行WPF应用开发过程中遇到多个内存泄漏的地方,昨天在WPF不明内存泄露已解决,白头发也没了中讲到了如何解决由于属性跟踪事件强引用导致的内存泄漏问题,本篇介绍一下由于 ...

  5. 内存泄露一个经典例子

    这个程序测试后会有什么结果?[美国某著名计算机嵌入式公司2005年9月面试题] 解析:毛病出在函数GetMemory中.void GetMemory(char *p, int num)中的*p实际上是 ...

  6. java 导致内存泄露的情况_JConsole定位内存泄漏

    在本文中,我们将看到Java中内存泄漏的示例代码.之后,我们将把Java应用程序连接到JConsole,比较有无内存泄漏时应用程序的内存使用情况.深入研究JConsole的内存监控工具可以让我们看到堆 ...

  7. java内存泄露direct_详解SpringCloudGateway内存泄漏问题

    SpringCloudGateway内存泄漏问题 项目完善差不多,在进入压力测试阶段期间,发现了gateway有内存泄漏问题,问题发现的起因是,当时启动一台gateway,一台对应的下游应用服务,在压 ...

  8. chrome内存泄露(一)、内存泄漏分析工具

    内存分析使用的工具包括chrome任务管理器.chrome时间轴(低版本是Timeline,高版本对应performance).chrome memory(低版本是chrome profiles,主要 ...

  9. java避免内存泄露_Java防止非静态内部类内存泄漏

    内存泄漏 一个不会被使用的对象,因为另一个正在使用的对象持有该对象的引用,导致它不能正常被回收,而停留在堆内存中,从而导致内存泄漏. 最坏的情况下,由于大量的内存泄漏,最终导致jvm的内存耗尽,致使程 ...

最新文章

  1. 微软正式开源Blazor ,将.NET带回到浏览器
  2. 什么是好的API设计?
  3. 【收藏】生产订单业务流程
  4. Centos-启动network报错RTNETLINK answers: File exists解决方法
  5. 开源作者在行动:疫情防控相关开源项目推荐
  6. 苹果6s最大屏幕尺寸_iPhone 6s:经典的小屏旗舰,百元价位也能做苹果党
  7. 用ASP.NET刷新页面的几种有效方法
  8. CSS3+HTML5特效5 - 震动的文字
  9. java 水仙花数问题(java50道经典编程题)
  10. 三角波fft的c语言程序设计,dsp的fft实现设计报告.docx
  11. 004-集成maven和Spring boot的profile功能打包
  12. java retainall_Java ArrayList retainAll() 使用方法及示例
  13. 京东联盟导购平台开发指南(附带API接口)
  14. 互联网发展的四个阶段总结
  15. java ftp 卡死_ftpclient卡死问题
  16. 影响一生的32步电影
  17. 程序员的高考题又来了
  18. java动态创建代理对象
  19. sklearn OneHot编码
  20. android compose webview视频播放横竖屏切换

热门文章

  1. Floyd Warshall算法
  2. Java Hashtable containsValue()方法与示例
  3. c语言插入排序算法_插入排序算法,流程图和C,C ++代码
  4. RabbitMQ中7种消息队列和保姆级代码演示!
  5. plsql查询乱码问题解决
  6. JAVA类(手机充电、放音乐示例)
  7. 算法复习第四章动态规划
  8. python爬虫 asyncio aiohttp aiofiles 单线程多任务异步协程爬取图片
  9. 微信开发3之php模板信息推送
  10. Navicat for MySQL工具创建mysql数据库定时器