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

点击蓝字

eb0d17ffdef7dfa7a676daf84a3f82a6.png

关注我们

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“的地方,保证内存被正确释放。

*声明:本文于网络整理,版权归原作者所有,如来源信息有误或侵犯权益,请联系我们删除或授权事宜。

4ac7057faa90fde9d5b83bf7f2bfb354.png

6ddaf720c063874c1461f9835d7347e5.gif

戳“阅读原文”我们一起进步

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/337427.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python发送邮件outlook_通过Python发送Outlook电子邮件?

I am using Outlook 2003. What is the best way to send email (through Outlook 2003) using Python? 解决方案 For a solution that uses outlook see TheoretiCALs answer below. Otherwise, use the smtplib that comes with python. Note that this will require your e…

C++队列queue用法详解(超详细)

点击蓝字关注我们一、定义queue是一种容器转换器模板&#xff0c;调用#include< queue>即可使用队列类。二、queue初始化queue<Type, Container> (<数据类型&#xff0c;容器类型>&#xff09;初始化时必须要有数据类型&#xff0c;容器可省略&#xff0c;省…

python随机抽取人名_python实现艾宾浩斯背单词功能,实现自动提取单词、邮件发送,再也不用担心背单词啦...

&#xfeff;已经完成了利用python爬虫实现定时QQ邮箱推送英文文章&#xff0c;辅助学习英语的项目&#xff0c;索性就一口气利用python多做一些自动化辅助英语学习的项目&#xff0c;对自己的编程能力和英文水评也有一定的帮助&#xff0c;于是在两天的努力下&#xff0c;我完…

用不到125行C语言代码就可以编写一个简单的16位虚拟机?

点击蓝字关注我们一位国外的软件工程师分享了这么一篇博文&#xff1a;Writing a simple 16 bit VM in less than 125 lines of C&#xff08;用不到 125 行 C 语言编写一个简单的 16 位虚拟机&#xff09;。博文地址&#xff1a;https://www.andreinc.net/2021/12/01/writing-…

用一个程序生成另一个程序_还有另一个报告生成器?

用一个程序生成另一个程序如果您具有业务应用程序开发的经验&#xff0c;那么很可能会遇到要求该应用程序具有灵活的报告机制的需求。 我工作的公司主要专注于开发业务解决方案&#xff0c;而报告是必不可少的&#xff0c;实际上&#xff0c;它必须包含我们开发的所有企业系统的…

CocosCreator1.x实现水流动的效果

CocosCreator1.x实现水流动的效果Cocos Creator版本&#xff1a;1.10.2 运行结果&#xff1a;(H5和原生都支持) 场景: 脚本&#xff1a; HelloWorld.js&#xff1a; let shader require(shader);cc.Class({extends: cc.Component,properties: {water: cc.Node,waterNorm…

python爬虫xpath教程_使用 Xpath 进行爬虫开发

使用 Xpath 进行爬虫开发 Xpath( XML Path Language, XML路径语言)&#xff0c;是一种在 XML 数据中查找信息的语言&#xff0c;现在&#xff0c;我们也可以使用它在 HTML 中查找需要的信息。 既然谈到 Xpath 是一门语言&#xff0c;当然它就会有自己的一些特定的语法。我们这里…

用C语言写烟花,给心中的那个人看!

点击蓝字关注我们前言程序员不懂浪漫? 大错特错&#xff01;今天就让你们看看什么是程序员的浪漫&#xff01;你向窗外看烟花&#xff0c;我在窗边看你&#xff0c;这时&#xff0c;你比烟花好看的多&#xff0c;你的眼眸倒映满天的烟火&#xff0c;我的瞳孔倒映你温柔的脸庞…

手把手教你做一个线程池--C语言版

点击蓝字关注我们1、线程池原理我们使用线程的时候就去创建一个线程&#xff0c;这样实现起来非常简便&#xff0c;但是就会有一个问题&#xff1a;如果并发的线程数量很多&#xff0c;并且每个线程都是执行一个时间很短的任务就结束了&#xff0c;这样频繁创建线程就会大大降低…

oracle 48小时内_缺血性脑梗死后48小时内使用阿替普酶能够降低脑损伤程度

一项刊登在影响因子7.6杂志Neurology上题为“Effect of IV alteplase on the ischemic brain lesion at 24–48 hours after ischemic stroke”的研究报告中&#xff0c;来自爱丁堡大学的科学家们发现&#xff0c;alteplase与病变可视性的短期进展降低相关。在荟萃分析中&#…

MySQL夺命16问,你能坚持到第几问?

点击蓝字关注我们1、数据库三大范式是什么&#xff1f;第一范式&#xff1a;每个列都不可以再拆分。第二范式&#xff1a;在第一范式的基础上&#xff0c;非主键列完全依赖于主键&#xff0c;而不能是依赖于主键的一部分。第三范式&#xff1a;在第二范式的基础上&#xff0c;非…

美图手机投射功能在哪_在Java 8中进行投射(还有其他功能?)

美图手机投射功能在哪将实例转换为设计不良的类型。 尽管如此&#xff0c;在某些情况下没有其他选择。 从第一天开始&#xff0c;执行此功能就已成为Java的一部分。 我认为Java 8提出了对这种古老技术稍加改进的需求。 静态铸造 Java中最常见的转换方法如下&#xff1a; 静态…

js箭头函数和普通函数区别

js箭头函数和普通函数区别实验环境&#xff1a;nodejs v12.16.1 箭头函数不能作为构造函数&#xff0c;而普通函数可以 箭头函数没有原型&#xff0c;而普通函数有 箭头函数return可以省略语句块。(如果>右边不是语句块&#xff0c;则代表return右边的表达式或对象) 箭…

git 更新_[技术分享T.191212]GitLab使用方法及git命令常见问题(不断更新)

该文章用于记录一些GitLab的使用指南&#xff0c;以及在实际版本控制过程中遇到的问题及解决方法&#xff0c;会尽量及时的更新~GitLab简介&#xff1a;GitLab和GitHub很相似都属于仓库管理系统的开源项目&#xff0c;使用Git作为代码管理工具&#xff0c;并在此基础上搭建起来…

记一次开发实战-对提供接口的C/C++进行二次开发

点击蓝字关注我们一、需求描述我有一个USB5538的库和头文件&#xff0c;并通过头文件提供了接口&#xff0c;我想把它更改一下&#xff0c;编译成python可调用的模块。二、创建工程及其目录1、创建空项目2、创建目录三、创建文件1、复制文件并添加2、添加新文件并写入四、环境配…

C++是如何实现多态的

C是如何实现多态的结论&#xff1a;C通过虚函数来实现多态的&#xff0c;根本原因是派生类和基类的虚函数表的不同。 构成多态的必要条件有如下3点&#xff1a; 存在继承关系基类存在虚函数&#xff0c;且派生类有相同原型的函数遮蔽它存在基类类型的指针指向派生类对象&…

C语言实现通讯录附详细代码(动态+静态)

点击蓝字关注我们一、通讯录简介实现一个通讯录&#xff1b;通讯录可以用来存储1000个人的信息&#xff0c;每个人的信息包括&#xff1a;姓名、性别、年龄、电话、住址提供方法&#xff1a;添加联系人信息删除指定联系人信息查找指定联系人信息修改指定联系人信息显示所有联系…

Lua协程Coroutine是什么

Lua协程Coroutine是什么协程和线程不同&#xff1a; 同一时刻&#xff0c;一个多线程程序可以用多个线程同时执行&#xff1b;而协程只能有一个在执行多线程是抢占式的&#xff1b;而协程是非抢占式的&#xff0c;只有协程显示被挂起&#xff0c;才会被挂起 协程和线程的相同…

C++程序的内存分区模型-栈区堆区

点击蓝字关注我们1、栈区&#xff1a;由编译器自动分配释放&#xff0c;存放函数的参数值&#xff0c;局部变量等&#xff08;由编译器管理其“生死”&#xff09;注意事项&#xff1a;不要返回局部变量的地址&#xff0c;栈区开辟的数据由编译器自动释放栈区代码演示&#xff…

CocosStudio的节点如何使用自定义shader

CocosStudio的节点如何使用自定义shader问题&#xff1a;我想对CocosStudio 的 某个UI 里的 某个图片&#xff08;如下图所示的Image类型&#xff09;使用自定义shader。但是&#xff0c;我把 对传统的cc.Sprite应用自定义shader的方式 应用于它时&#xff0c;并不生效&#xf…