0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

C语言内存泄露问题很严重,如何应对?

电子设计 来源:电子设计 作者:电子设计 2020-10-30 09:58 次阅读

1. 前言
最近部门不同产品接连出现内存泄漏导致的网上问题,具体表现为单板在现网运行数月以后,因为内存耗尽而导致单板复位现象。

一方面,内存泄漏问题属于低级错误,此类问题遗漏到现网,影响很坏;另一方面,由于内存泄漏问题很可能导致单板运行固定时间以后就复位,只能通过批量升级才能解决,实际影响也很恶劣。

同时,接连出现此类问题,尤其是其中一例问题还是我们老员工修改引入,说明我们不少员工对内存泄漏问题认识还是不够深刻的。

本文通过介绍内存泄漏问题原理及检视方法,希望后续能够从编码检视环节就杜绝此类问题发生。

说明:预防内存泄漏问题有多种方法,如加强代码检视、工具检测和内存测试等,本文聚集于开发人员能力提升方面。

2. 内存泄漏问题原理
2.1 堆内存在 C 代码中的存储方式
内存泄漏问题只有在使用堆内存的时候才会出现,栈内存不存在内存泄漏问题,因为栈内存会自动分配和释放。

C 代码中堆内存的申请函数是 malloc,常见的内存申请代码如下:

左右滑动查看全部代码>>>

char *info = NULL; /**转换后的字符串**/
info = (char*)malloc(NB_MEM_SPD_INFO_MAX_SIZE);
if( NULL == info)
{
(void)tdm_error("malloc error!/n");
return NB_SA_ERR_HPI_OUT_OF_MEMORY;
}

由于 malloc 函数返回的实际上是一个内存地址,所以保存堆内存的变量一定是一个指针(除非代码编写极其不规范)。

再重复一遍,保存堆内存的变量一定是一个指针,这对本文主旨的理解很重要。当然,这个指针可以是单指针,也可以是多重指针。

malloc 函数有很多变种或封装,如 g_malloc、g_malloc0、VOS_Malloc 等,这些函数最终都会调用 malloc 函数。

2.2 堆内存的获取方法
看到本小节标题,可能有些同学有疑惑,上一小节中的 malloc 函数,不就是堆内存的获取方法吗?

的确是,通过 malloc 函数申请是最直接的获取方法,如果只知道这种堆内存获取方法,就容易掉到坑里了。一般的来讲,堆内存有如下两种获取方法:

方法一:将函数返回值直接赋给指针,一般表现形式如下:

左右滑动查看全部代码>>>

char *local_pointer_xx = NULL;
local_pointer_xx = (char*)function_xx(para_xx, …);


该类涉及到内存申请的函数,返回值一般都指针类型,例如:

左右滑动查看全部代码>>>

GSList* g_slist_append (GSList *list, gpointer data);


方法二:将指针地址作为函数返回参数,通过返回参数保存堆内存地址,一般表现形式如下:

左右滑动查看全部代码>>>

int ret;
char *local_pointer_xx = NULL; /**转换后的字符串**/
ret = (char*)function_xx(..., &local_pointer_xx, ...);


该类涉及到内存申请的函数,一般都有一个入参是双重指针,例如:

左右滑动查看全部代码>>>

__STDIO_INLINE _IO_ssize_t;
getline (char **__lineptr, size_t *__n, FILE *__stream);
前面说通过 malloc 申请内存,就属于方法一的一个具体表现形式。其实这两类方法的本质是一样的,都是函数内部间接申请了内存,只是传递内存的方法不一样,方法一通过返回值传递内存指针,方法二通过参数传递内存指针。

2.3 内存泄漏三要素
最常见的内存泄漏问题,包含以下三个要素:

要素一:函数内有局部指针变量定义;

要素二:对该局部指针有通过上一小节中“两种堆内存获取方法”之一获取内存;

要素三:在函数返回前(含正常分支和异常分支)未释放该内存,也未保存到其它全局变量或返回给上一级函数。

2.4 内存释放误区
稍微使用过 C 语言编写代码的人,都应该知道堆内存申请之后是需要释放的。但为何还这么容易出现内存泄漏问题呢?

一方面,是开发人员经验不足、意识不到位或一时疏忽导致;另一方面,是内存释放误区导致。很多开发人员,认为要释放的内存应该局限于以下两种:

1) 直接使用内存申请函数申请出来的内存,如 malloc、g_malloc 等;

2)该开发人员熟悉的接口中,存在内存申请的情况,如 iBMC 的兄弟,都应该知道调用如下接口需要释放 list 指向的内存:

左右滑动查看全部代码>>>

dfl_get_object_list(const char* class_name, GSList **list);
按照以上思维编写代码,一旦遇到不熟悉的接口中需要释放内存的问题,就完全没有释放内存的意识,内存泄漏问题就自然产生了。

3. 内存泄漏问题检视方法
检视内存泄漏问题,关键还是要养成良好的编码检视习惯。与内存泄漏三要素对应,需要做到如下三点:

1) 在函数中看到有局部指针,就要警惕内存泄漏问题,养成进一步排查的习惯

2) 分析对局部指针的赋值操作,是否属于前面所说的“两种堆内存获取方法”之一,如果是,就要分析函数返回的指针到底指向啥?

是全局数据、静态数据还是堆内存?对于不熟悉的接口,要找到对应的接口文档或源代码分析;又或者看看代码中其它地方对该接口的引用,是否进行了内存释放;

3) 如果确认对局部指针存在内存申请操作,就需要分析该内存的去向,是会被保存在全局变量吗?又或者会被作为函数返回值吗?如果都不是,就需要排查函数所有有”return“的地方,保证内存被正确释放。

内存泄漏是比较难查的 bug 之一?有什么查找技巧吗?欢迎留言交流~

审核编辑 黄昊宇

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • C语言
    +关注

    关注

    180

    文章

    7534

    浏览量

    128830
  • 内存泄露
    +关注

    关注

    0

    文章

    6

    浏览量

    1935
收藏 人收藏

    评论

    相关推荐

    使用position2go雷达进行测距时,测量值变得异常的原因?

    数据极小,而rx1则出现了很严重泄露(5.81m处的是泄露,1.5m处才是真实物体),这明显并非正常状态。 求助是否是因为雷达被损坏(外表并没有损伤,也没有不合规的使用),是否有其他人也遇到了类似的问题。
    发表于 03-06 07:09

    N9H20K51串口接收中断,数据丢失严重怎么解决?

    N9H20K51这个型号的片子,串口1有个16字节的缓冲区,我设置1个字节中断一次,当发送的数据小于16字节时,数据都很正常,当发送大量数据时,数据丢失很严重,请问你们有遇到这样了吗,官方的例程试过了,测试不行!请教一下问题所在。
    发表于 01-17 06:39

    Z450-4A的500KW直流电机换向器打火很严重是什么原因导致的呢?

    有一台Z450-4A的500KW直流电机,最近出现了很奇怪的现象,换向器打火很严重,换向器出现下面图片上的迹象,间隔着有打火的现象。已经对碳刷全部更换,用砂纸对换向器进行了打磨,处理后依然是打火严重
    发表于 01-09 06:39

    PT断线是什么?为什么说PT断线影响很严重

    PT断线是什么?为什么说PT断线影响很严重? PT断线是指电压互感器的一种故障状态,即PT缺乏或中断了电压信号的传输。PT作为一种重要的电气元件,主要用于将高压系统的电压降到安全范围内,以供电力仪表
    的头像 发表于 12-26 16:01 1506次阅读

    全志R128内存泄露调试案例

    内存泄露调试案例 问题背景 硬件:R128 软件:FreeRTOS + rtplayer_test(Cedarx)+ AudioSystem 问题复现 复现步骤: rtplayer_test
    发表于 12-11 10:57

    利用AD734作倍频,经过倍频后讯号的dc偏移很严重是为什么?

    各位好 最近再利用AD734作倍频,参考资料手册内图24之电路,并将第1与第6脚短路灌入输入讯号,并将第10pin接地, 其输出结果可发现到是可以接输入讯号成功倍频,但经过倍频后讯号的dc偏移很严重
    发表于 11-21 08:14

    内存是如何泄露

    作为 C++ 程序员,内存泄露始终是悬在头上的一颗炸弹。在过去几年的 C++ 开发过程中,由于我们采用了一些技术,我们的程序发生内存泄露的情况屈指可数。今天就在这里向大家做一个简单的介
    的头像 发表于 11-13 14:13 226次阅读
    <b class='flag-5'>内存</b>是如何<b class='flag-5'>泄露</b>的

    mtrace分析内存泄露

    一、mtrace分析内存泄露 mtrace(memory trace),是 GNU Glibc 自带的内存问题检测工具,它可以用来协助定位内存泄露
    的头像 发表于 11-13 10:55 947次阅读
    mtrace分析<b class='flag-5'>内存</b><b class='flag-5'>泄露</b>

    内存泄漏如何避免

    的数,那就是内存溢出。 2. 内存泄漏 内存泄露 memory leak,是指程序在申请内存后,无法释放已申请的
    的头像 发表于 11-10 11:04 378次阅读
    <b class='flag-5'>内存</b>泄漏如何避免

    PT断线是什么意思?为什么说PT断线影响很严重

     我们首先了解PT断线是什么。PT是电压互感器的英文符号,电压互感器断线,在电力电气生产活动中是一种比较常见的故障。一旦PT断线失压,对保护、计量、测量等操作的准确性和可靠性,均会产生至关重要的影响。
    发表于 09-14 15:28 1134次阅读
    PT断线是什么意思?为什么说PT断线影响<b class='flag-5'>很严重</b>?

    使用C语言内存泄露过吗?

    C语言是一种面向过程的编程语言,它广泛应用于操作系统、嵌入式系统、网络设备等方面,因其高效、灵活和可控的特性而备受青睐。
    发表于 09-06 11:27 249次阅读
    使用C<b class='flag-5'>语言</b>你<b class='flag-5'>内存</b><b class='flag-5'>泄露</b>过吗?

    N9H20K51串口接收中断,数据丢失严重如何解决?

    N9H20K51这个型号的片子,串口1有个16字节的缓冲区,我设置1个字节中断一次,当发送的数据小于16字节时,数据都很正常,当发送大量数据时,数据丢失很严重,请问你们有遇到这样了吗,官方的例程试过了,测试不行!请教一下问题所在。
    发表于 09-04 08:00

    glibc导致的堆外内存泄露的排查过程

    本文记录一次glibc导致的堆外内存泄露的排查过程。
    的头像 发表于 09-01 09:43 411次阅读
    glibc导致的堆外<b class='flag-5'>内存</b><b class='flag-5'>泄露</b>的排查过程

    使用valgrind对代码进行内存泄露检测

    代码可能存在内存泄露怎么办?
    发表于 08-21 15:30 172次阅读
    使用valgrind对代码进行<b class='flag-5'>内存</b><b class='flag-5'>泄露</b>检测

    电动机发热很严重的常见原因是什么

    电机作为人们生产和生活中不可缺少的重要的动力提供者,在使用的过程中很多的电机会出现发热很严重的现象,但是很多时候不知道怎么去解决,更加严重的是不知道是什么原因导致的电机发热,
    的头像 发表于 07-24 14:49 596次阅读