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

    文章

    7591

    浏览量

    135770
  • 内存泄露
    +关注

    关注

    0

    文章

    6

    浏览量

    1977
收藏 人收藏

    评论

    相关推荐

    TPA3118按照datasheet画的电路,结果电感发热很严重,怎么解决?

    按照datasheet画的电路,结果电感发热很严重,求大神解答
    发表于 10-28 07:50

    利用TLV320AIC3256做了一个带话筒的设备,发现啸叫很严重,怎么解决?

    本公司做了一个带话筒的设备,发现啸叫很严重,不知道这个要怎么去掉,我看了一下TLV320AIC3256这个型号说有AEC回声消除功能,不知道能不能满足我的要求,想请问一下有没有大神做个类似设备
    发表于 10-24 07:28

    THS4302在10M到40M之间为什么失真很严重,怎么解决?

    在10M到40M之间为什么失真很严重。 电路是按数据手册搭的,+4V和-4V供电,输入用50Ω到GND;输出100Ω到GND。 接+5V和-5V供电时芯片发热很严重。 不知道是不是我电路有问题?还是芯片自身的问题?
    发表于 09-24 08:02

    VCA820按照datasheet上的电路搭的,但是出来的波形很粗,自激现象很严重怎么解决?

    按照datasheet上的电路搭的,但是出来的波形很粗,自激现象很严重 急求帮助啊!!!
    发表于 09-18 08:50

    ISO124U发热很严重是怎么回事?

    我电路用的是ISO124U,原边供电电压±12V,副边供电电压±15V。芯片工作时输入电压+7V,输出电压+7V正常,但是芯片发热很严重,通电半分钟芯片就比较烫了,功耗也很明显,不知道这种情况是否正常,该正常工作时发热很严重吗?我不知道是不是我的芯片有问题?求解啊,谢
    发表于 09-12 07:23

    使用哪种运放比较适合做衰减用,且不会失真很严重

    您好:我想用运放做衰减用,输入信号的幅度为0~10V,衰减5倍左右。输入信号的频率为135H和15Hz组成的正弦波包络。 请问,使用哪种运放比较适合做衰减用,且不会失真很严重,谢谢!
    发表于 09-10 07:20

    THS3202使用的时候发烫很严重,为什么?

    THS3202使用的时候发烫很严重
    发表于 09-02 08:04

    E类功放与线圈实现无线供电传输,MOS管发热很严重的原因?

    最近在研究E类功放,采用E类功放与线圈实现无线供电传输。 但是这个E类功放部分,MOS管发热很严重,应该是输出端阻抗匹配的问题,请教一下给位。 (MOS管用的是CSD16322Q5,驱动管用的是UCC27517A)
    发表于 09-02 06:37

    INA128放大小信号抖动很严重怎么解决?

    怎样解决放大器放大小信号都懂很严重的问题?或则有没有哪种仪表运放放大微弱信号抖动不会很严重
    发表于 08-23 08:24

    TL3016输入正弦波的频率超过20MHz时,输出波形出现很严重的振荡怎么解决?

    当输入正弦波的频率超过20MHz 时,输出波形出现很严重的振荡,原理图如下
    发表于 08-07 07:02

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

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

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

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

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

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

    内存是如何泄露

    作为 C++ 程序员,内存泄露始终是悬在头上的一颗炸弹。在过去几年的 C++ 开发过程中,由于我们采用了一些技术,我们的程序发生内存
    的头像 发表于 11-13 14:13 391次阅读
    <b class='flag-5'>内存</b>是如何<b class='flag-5'>泄露</b>的

    内存泄漏如何避免

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