C语言内存泄露很严重,如何应对?
source link: https://segmentfault.com/a/1190000023845042
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
摘要: 通过介绍内存泄漏问题原理及检视方法,希望后续能够从编码检视环节就杜绝内存泄漏导致的网上问题发生。
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“的地方,保证内存被正确释放。
Recommend
-
53
国外媒体Motherboard网络安全记者Lorenzo Franceschi-Bicchierai撰文揭秘从事SIM卡劫持的黑客。作者探访了买卖社交媒体和游戏账号的论坛OGUSERS,那些账号往往是通过“SIM卡劫持”盗取的。 通过SIM卡劫持,黑客盗用目标对...
-
8
应对内部数据泄露威胁的安全保密实践 – 安全意识博客Skip to content 最近,在网络安全博主圈子的一篇文章中,有百余位网络安全顾问专家一致表示:内部...
-
7
剪切板上的隐私泄露,真的很严重非著名程序员公众号「非著名程序员」主理人,程序员/复业者/生涯规划师
-
4
如何检测及应对数据泄露 – 安全意识博客Skip to content 您可能经常会从媒体上了解到一些数据泄露事故案例,但是您有没有想一想,这些数据泄露事故...
-
9
数据泄露事件频发,企业该如何应对应用数据安全问题? - IT业界_CIO时代网 - CIO时代—新技术、新商业、新管理数据泄露事件频发,企业该如何应对应用数据安全问题? 2021-11-22 14:33:22 来源: 摘要:随着...
-
7
AMD EPYC 7003X系列CPU规格和售价泄露,加了3D V-Cache后涨价严重
-
2
21世纪严重的15起数据泄露事件 作者:小二郎 2022-11-14 12:38:29 安全 根据受影响的用户、暴露的记录或受影响的帐户数量,我们总结...
-
3
云数据泄露和复杂性上升,如何应对安全挑战? 作者:肖力 翻译 2022-12-27 08:00:28 尽管云服务越来越普遍和使用,但企业对云服务日益复杂有着共同的担忧,大多数(51%)的IT专业人员同意在云中管理隐私和数据保护...
-
3
V2EX › 宽带症候群 使用 clash 上网时应对 dns 泄露的心得
-
15
CISO应对数据泄露后如何规避个人责任 责任编辑:cres 作者:Daniel B. Garrie | 2024-04-30 17:19:14 原创文章 企业网D1Net 数据泄露对公司、其人员、客户以及广泛的其他人员都可能产生重大的财务、声誉、法律和...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK