c语言内存泄漏严重的解决方法

摘要:通过介绍内存泄漏问题原理及检视方法,希望后续能够从编码检视环节就杜绝内存泄漏导致的网上问题发生。

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

以上就是c语言内存泄漏严重的解决方法的详细内容,更多关于c语言内存泄漏的资料请关注我们其它相关文章!

(0)

相关推荐

  • C语言 动态内存分配的详解及实例

    1. 动态内存分配的意义 (1)C 语言中的一切操作都是基于内存的. (2)变量和数组都是内存的别名. ①内存分配由编译器在编译期间决定 ②定义数组的时候必须指定数组长度 ③数组长度是在编译期就必须确定的 (3)但是程序运行的过程中,可能需要使用一些额外的内存空间 2. malloc 和 free 函数 (1)malloc 和 free 用于执行动态内存分配的释放 (2)malloc 所分配的是一块连续的内存 (3)malloc 以字节为单位,并且返回值不带任何的类型信息:void* mallo

  • C语言 动态内存分配详解

    C语言 动态内存分配详解 动态内存分配涉及到堆栈的概念:堆栈是两种数据结构.堆栈都是数据项按序排列的数据结构,只能在一端(称为栈顶(top))对数据项进行插入和删除. 栈(操作系统):由操作系统自动分配释放 ,存放函数的参数值,局部变量的值等.其操作方式类似于数据结构中的栈. 堆(操作系统): 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收,分配方式倒是类似于链表. \在C语言中,全局变量分配在内存中的静态存储区,非静态的局部变量(包括形参)是分配在内存的动态存储区,该存储区被

  • C++程序检测内存泄漏的方法分享

    一.前言 在Linux平台上有valgrind可以非常方便的帮助我们定位内存泄漏,因为Linux在开发领域的使用场景大多是跑服务器,再加上它的开源属性,相对而言,处理问题容易形成"统一"的标准.而在Windows平台,服务器和客户端开发人员惯用的调试方法有很大不同.下面结合我的实际经验,整理下常见定位内存泄漏的方法. 注意:我们的分析前提是Release版本,因为在Debug环境下,通过VLD这个库或者CRT库本身的内存泄漏检测函数能够分析出内存泄漏,相对而言比较简单.而服务器有很多问

  • C++内存泄漏及检测工具详解

    首先我们需要知道程序有没有内存泄露,然后定位到底是哪行代码出现内存泄露了,这样才能将其修复. 最简单的方法当然是借助于专业的检测工具,比较有名如BoundsCheck,功能非常强大,相信做C++开发的人都离不开它.此外就是不使用任何工具,而是自己来实现对内存泄露的监控,分如下两种情况: 一. 在 MFC 中检测内存泄漏 假如是用MFC的程序的话,很简单.默认的就有内存泄露检测的功能. 我们用VS2005生成了一个MFC的对话框的程序,发现他可以自动的检测内存泄露.不用我们做任何特殊的操作. 仔细

  • 易语言内存读取获得当前PC已经登陆微信号的代码

    取当前PC登陆微信号的代码 此功能需要加载精易模块5.6 .版本 2 .程序集 窗口程序集_启动窗口 .子程序 __启动窗口_创建完毕 .局部变量 局部_登陆个数, 整数型 .局部变量 局部_微信号, 文本型, , "0" .局部变量 i, 整数型 局部_登陆个数 = 取当前登陆微信号 (局部_微信号) .计次循环首 (局部_登陆个数, i) 微信号编辑框.内容 = "当前PC登陆微信号:" + 局部_微信号 [i] .计次循环尾 () .子程序 取当前登陆微信号,

  • 详谈C++的内存泄漏问题

    1)有多少new就有多少delete.而且配对的new与delete要尽量在一个函数中.如果子函数中需要返回的数据是通过new来创建的,我的处理方式一般是在需要调用这个函数的位置将对应的数据规模创建好,并且通过指针或是引用传递到子函数中. 2)本人比较粗心大意,又一次在编码的过程中 竟然将delete语句放在了return语句的后面,导致程序运行的过程中会因内存不足二崩溃.检查了不下20遍才检查出来,真是哭的心情都有了.希望大家以我为戒,一定把return语句放在函数的最后面,估计也就我一个人犯

  • 浅析c语言中的内存

    1.栈(stack):存局部变量.函数,调用函数时会开辟栈区,函数结束时就自动回收,遵循后进先出的原则,从高地址向低地址增长. 2.堆(heap):malloc.realloc.calloc等开辟的内存就在堆,从低地址向高地址增长,由程序员分配和释放,系统不自动回收,所以一定要记得申请了就要释放,以免溢出. 3.数据段(初始化数据段)(data):存放初始化的全局变量.static修饰的已初始化的变量. 4.未初始化数据段(bss段):存放未初始化的全局变量和static修饰的未初始化的变量.

  • C++中关于Crt的内存泄漏检测的分析介绍

    尽管这个概念已经让人说滥了 ,还是想简单记录一下, 以备以后查询. 复制代码 代码如下: #ifdef _DEBUG#define DEBUG_CLIENTBLOCK   new( _CLIENT_BLOCK, __FILE__, __LINE__)#else#define DEBUG_CLIENTBLOCK#endif#define _CRTDBG_MAP_ALLOC#include <crtdbg.h>#ifdef _DEBUG#define new DEBUG_CLIENTBLOCK#e

  • C语言动态内存分配的详解

    C语言动态内存分配的详解 1.为什么使用动态内存分配 数组在使用的时候可能造成内存浪费,使用动态内存分配可以解决这个问题. 2. malloc和free C函数库提供了两个函数,malloc和free,分别用于执行动态内存分配和释放. (1)void *malloc(size_t size); malloc的参数就是需要分配的内存字节数.malloc分配一块连续的内存.如果操作系统无法向malloc提供更多的内存,malloc就返回一个NULL指针. (2)void free(void *poi

  • c语言内存泄漏严重的解决方法

    摘要:通过介绍内存泄漏问题原理及检视方法,希望后续能够从编码检视环节就杜绝内存泄漏导致的网上问题发生. 1. 前言 最近部门不同产品接连出现内存泄漏导致的网上问题,具体表现为单板在现网运行数月以后,因为内存耗尽而导致单板复位现象.一方面,内存泄漏问题属于低级错误,此类问题遗漏到现网,影响很坏:另一方面,由于内存泄漏问题很可能导致单板运行固定时间以后就复位,只能通过批量升级才能解决,实际影响也很恶劣.同时,接连出现此类问题,尤其是其中一例问题还是我们老员工修改引入,说明我们不少员工对内存泄漏问题认

  • java OOM内存泄漏原因及解决方法

    前言 这篇文章主要介绍了java OOM内存泄漏原因及解决方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 一.什么是OOM OOM,全称"Out Of Memory",翻译成中文就是"内存用完了",当JVM因为没有足够的内存来为对象分配空间并且垃圾回收器也已经没有空间可回收时,就会抛出这个error 二.为什么会OOM.出现的原因是什么 为什么会没有内存了呢?原因不外乎有两点: ① 分配的少了:比如虚拟机本身可

  • 教你用MAT工具分析Java堆内存泄漏问题的解决方法

    一.MAT概述与安装 MAT,全称Memory Analysis Tools,是一款分析Java堆内存的工具,可以快速定位到堆内泄漏问题.该工具提供了两种使用方式,一种是插件版,可以安装到Eclipse使用,另一种是独立版,可以直接解压使用. 我把独立版MAT安装包放到了网盘上,方便直接下载 链接: https://pan.baidu.com/s/1DVHlHuSfi_4TVl2ei5YuLA 提取码: 42qt 独立版解压后,其内部文件是这样的-- 这里有一个MemoryAnalyzer.in

  • Android内存泄漏的轻松解决方法

    前言 内存管理的目的就是让我们在开发过程中有效避免我们的应用程序出现内存泄露的问题.内存泄露相信大家都不陌生,我们可以这样理解:「没有用的对象无法回收的现象就是内存泄露」. 如果程序发生了内存泄露,则会带来以下这些问题 应用可用的内存减少,增加了堆内存的压力 降低了应用的性能,比如会触发更频繁的 GC 严重的时候可能会导致内存溢出错误,即 OOM Error 下面我们从基础说起 基础知识 Java 的内存分配简述 方法区(non-heap):编译时就分配好,在程序整个运行期间都存在.它主要存放静

  • 5个Android开发中比较常见的内存泄漏问题及解决办法

    android中一个对象已经不需要了,但是其他对象还持有他的引用,导致他不能回收,导致这个对象暂存在内存中,这样内存泄漏就出现了. 内存泄漏出现多了,会是应用占用过多的没存,当占用的内存超过了系统分配的内存容量,就会出现内存溢出了导致应用Crash. 了解了内存泄漏的原因及影响后,我们需要做的就是掌握常见的内存泄漏,并在以后的Android程序开发中,尽量避免它.下面搜罗了5个Android开发中比较常见的内存泄漏问题及解决办法,分享给大家,一起来看看吧. 一.单例造成的内存泄漏 android

  • 记一次python 内存泄漏问题及解决过程

    最近工作中慢慢开始用python协程相关的东西,所以用到了一些相关模块,如aiohttp, aiomysql, aioredis等,用的过程中也碰到的很多问题,这里整理了一次内存泄漏的问题 通常我们写python程序的时候也很少关注内存这个问题(当然可能我的能力还有待提升),可能写c和c++的朋友会更多的考虑这个问题,但是一旦我们的python程序出现了 内存泄漏的问题,也将是一件非常麻烦的事情了,而最近的一次代码中也碰到了这个问题,不过好在最后内存溢出不是我代码的问题,而是所用到的一个包出现了

  • 有关tomcat内存溢出的完美解决方法

    tomcat内存溢出设置JAVA_OPTS 答案1 设置Tomcat启动的初始内存 其初始空间(即-Xms)是物理内存的1/64,最大空间(-Xmx)是物理内存的1/4.可以利用JVM提供的-Xmn -Xms -Xmx等选项可 进行设置 三.实例,以下给出1G内存环境下java jvm 的参数设置参考: JAVA_OPTS="-server -Xms800m -Xmx800m -XX:PermSize=64M -XX:MaxNewSize=256m -XX:MaxPermSize=128m -D

  • vim配置go语言语法高亮问题的解决方法

    操作系统 : CentOS7.3.1611_x64 go 版本 : go1.8.3 linux/amd64 vim版本 :version 7.4.160 vim配置go语言语法高亮的问题已经遇到过好几次了,每次都去查找太麻烦,这里总结下. 安装git: yum install git 安装vim-go : cd ~ mkdir .vim cd .vim mkdir autoload plugged cd plugged git clone https://github.com/fatih/vim

  • 记一次django内存异常排查及解决方法

    起因 Django 作为 Python著名的Web框架,相信很多人都在用,自己工作中也有项目项目在用,而在最近几天的使用中发现,部署Django程序的服务器出现了内存问题,现象就是运行一段时间之后,内存占用非常高,最终会把服务器的内存耗尽,对于Python项目出现内存问题,自己之前处理过一次,所以并没有第一次解决时的慌张,自己之前把解决方法也整理了:https://www.jb51.net/article/151604.htm 但是事情似乎并没有我想的那么简单,自己尝试用之前的的方法tracem

  • docker启动elasticsearch时内存不足问题及解决方法

    问题 docker安装并启动elasticsearch时内存不足 系统centos8(阿里云ecs服务器) [root@iZ2zeczvvb79boy368xppwZ ~]# cat /etc/redhat-release CentOS Linux release 8.1.1911 (Core) 安装过程 docker pull elasticsearch:6.4.0 修改虚拟机内存(貌似没有效果) sysctl -w vm.max_map_count=262144 使用docker run命令

随机推荐