【C语言】关于内存泄漏的那些事
发布网友
发布时间:2024-09-27 05:59
我来回答
共1个回答
热心网友
时间:2024-10-02 06:31
1 嵌入式设备中,内存泄漏问题往往会影响到设备的正常运行,有长时间运行后程序复位、设备重启等形式,一旦出现此问题影响还是很严重的。
2 相关岗位的面试过程中,关于内存的理解是很重要的一方面。
2 什么叫内存泄漏?
堆内存的使用流程:申请->操作&使用->释放,整个过程是使用内存地址进行串联
内存泄漏是指在需要释放时没有被释放,或者无法释放。该内存就一直被占,无人释放也无人使用,内存空间本就宝贵,某段内存一直被占且无人使用且无法释放,就相当于该段内存无用了被迫遗弃了,故称之为内存泄漏。
如果这种无用的内存过多,就会造成正常程序无内存可用,严重的会造成程序崩溃,所以内存泄漏是比较严重的问题。
3 C语言内存基本分区简介
了解完内存泄漏,我们还需要了解内存的基本分类,清楚到底是什么样的内存容易泄漏。
对C语言来讲,内存的主要分区为:栈区、堆区、数据区、代码区、常量存储区,非只读的是前三种,栈区是系统自动分配释放,堆区则需要程序员手动申请释放,任何事情涉及到手动往往就会出问题,就比如今天聊的“内存泄漏”。
因为堆区无法想栈区一样自动分配和释放,需要程序员在自主管理,因此内存泄漏只会出现在堆内存中。
4 堆内存的获取方法
常规从堆中获取内存的方法为:使用malloc函数申请固定长度的内存,函数返回的是该段内存的首地址
实际使用过程中,malloc的操作往往是在某一函数中完成的,且大概率这一函数会向外传递申请到的内存指针,对于该函数传递指针的常用方法有两种
方法1:使用某函数返回值给指针赋值,如:
方法2:使用某函数的入参给双重指针赋值,如
5 错误案例描述
基于以上常规的基础操作,我们复现一下内存泄漏的经典案例
错误1:p_main在func_get_ptr中被替换,造成位置1申请的内存首地址被替换为位置2申请的内存,从而在main函数中释放p_main时实际释放的位置2的内存,位置1的内存没有被释放而泄漏
错误2:没有接收func_ret_ptr函数的返回值,程序继续执行,造成直接丢失了位置2申请的内存,内存泄漏
错误3:func_ret_ptr返回内存首地址后没有作free处理,造成内存泄漏
错误4:如果某个结构化元素需要申请堆内存,同时结构化元素内部也需要申请堆内存,释放时单纯释放了p_param结构体的内存,遗漏了p_content指针所指向的内存,一旦p_param被释放,p_content保存的地址也无从查起,造成内存泄漏。
6 总结内存泄漏的主要原因
1、指针内容被覆盖而无法释放:函数内有局部指针变量定义,对该局部指针有获取内存的操作,在函数返回前没有释放该内存,也未保存到其他全局变量或返回上一级函数。或者是某一函数指针覆盖了另一个指针,造成被覆盖的指针地址丢失而无法释放。如错误1
2、内存申请被遗忘:如错误2
3、申请内存和释放内存没有配对处理:如错误3
4、结构化数据中,外层指针被释放,内层指针数据丢失而无法释放:如错误4
7 如何检查内存泄漏?
1 自主申请的内存需要有释放内存的接口相配对,养成良好的编程习惯,特别是在结构化数据中需要多次申请内存时,内存地址作为函数返回值时也要注意是否被正确处理。
2 在对指针赋值前,一定要确保没有内存位置会变为孤立的。特别是对某函数中局部变量操作时。
3 如果有局部变量,并且有对局部变量赋值的操作,要检查函数的返回的指针到底是指向什么?是全局变量、静态数据还是堆内存?如果代码中有不熟悉的接口,要找到对应接口文档或源代码分析,保证不要出现不必要的错误;
4 如果函数中有对局部指针有内存申请的操作,那么要检查被保存的是全局变量吗?会被作为函数返回值吗?如果都不是的话,那要排查函数所有的“return”的地方,要保证内存被正确释放,不占用内存。
8 文章参考
https://blog.csdn.net/AuroraSmith/article/details/126647527
https://blog.csdn.net/weixin_28730665/article/details/117185882
http://c.biancheng.net/view/385.html
虽有参考,但实例和阐述为个人所写,转载请注明出处。
欢迎批评指正