如何有效预防内存泄漏?

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

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

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

相关文章

微信小程序基础

1.小程序发展史 微信小程序之前,是使用weixin-sdk进行开发,调用视频,摄像头等。 微信小程序weixin up端,所以PC端的window这些没有,运行环境是IOS,安卓等,有一些特殊的调用录音功能&#xff0…

JavaScript 安全的《加/解密处理》的实战--案例(二)

前言: 在Web开发中,安全性一直是一个重要而复杂的议题,尤其是与敏感数据操作有关时。数据传输地过程中需要保证信息绝对的安全性,包括了诸如用户名、密码、个人信息等,这就需要对这类信息进行加密与解密。本案例(二&a…

java google.zxing解析二维码工具类

文章目录 pom代码解析用例生成二维码用例 pom <dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.3.0</version> </dependency>代码 import com.google.zxing.*; import com.google…

通俗理解Jenkins是什么?

目录 通俗理解 Jenkins是什么&#xff1f; 通俗理解 假设你有一个软件项目&#xff0c;多个开发者在一起写代码。每当有人提交新的代码时&#xff0c;你想要自动地构建、测试这些代码&#xff0c;确保它们没有引入问题。 Jenkins就像一个聪明的助手&#xff0c;会在有人提交…

【数据仓库-10】-- 数据仓库、数据湖和湖仓一体对比

目录 1 数据仓库与数据库的对比 2 数据湖与数据仓库的对比 3 数据仓库、数据湖和湖仓一体

检查 `/var` 是否有自己的独立分区

要检查 /var 是否有自己的独立分区&#xff0c;您可以使用以下方法&#xff1a; 1. 使用 df 命令 df 命令&#xff08;磁盘文件系统&#xff09;可以用来报告文件系统的磁盘空间使用情况。要查看 /var 的情况&#xff0c;请运行&#xff1a; df -h /var这个命令会显示 /var …

在AWS Lambda中使用FFmpeg处理m3u8视频流

大纲 1 部署有FFmpeg功能的Lambda环境1.1 部署层1.2 部署代码1.2.1 FFmpeg指令1.2.2 代码 2 配置Lambda角色权限2.1 选择角色类型2.2 设置权限2.3 保存角色2.4 绑定角色 参考文献 在直播里领域&#xff0c;我们经常需要对视频流进行处理。FFmpeg则是该领域中处理的利器。这篇文…

根文件系统的开机自启动测试

一. 简介 本文在之前制作的根文件系统可以正常运行的基础上进行的&#xff0c;继上一篇文章地址如下&#xff1a; 完善根文件系统-CSDN博客 在前面测试软件hello 运行时&#xff0c;都是等 Linux 启动进入根文件系统以后手动输入 “./hello” 命令 来完成的。 我们一般做好产…

C++:一个函数返回值的小问题

今天一位同学问了我这样一个问题&#xff1a; int& getDState() { return _dstate; } int getDState() { return _dstate; }这两个函数有什么区别&#xff1f; 这两个返回一个名为 _dstate 的成员变量或变量。函数的返回类型不同&#xff0c;在C中是不允许的&#xff0c;…

Python计算方差

方差可以反应变量的离散程度&#xff0c;是因为它度量了数据点与均值的差异。方差是每个数据点与均值的差的平方和的平均值&#xff0c;它可以反映数据点在均值附近的分布情况。如果方差较小&#xff0c;说明数据点更加集中在均值附近&#xff0c;离散程度较小&#xff1b;如果…

uniapp微信小程序分包,小程序分包

前言&#xff0c;都知道我是一个后端开发、所以今天来写一下uniapp。 起因是美工给我的切图太大&#xff0c;微信小程序不让了&#xff0c;在网上找了一大堆分包的文章&#xff0c;我心思我照着写的啊&#xff0c;怎么就一直报错呢&#xff1f; 错误原因 tabBar的页面被我放在分…

【JSD1209考试】题目与解答

选择题 在Java Applet程序中&#xff0c;如果对发生的事件做出响应和处理的时候&#xff0c;应该使用的语句是&#xff1f; ( C ) &#xff08;1分&#xff09; A. import java.awt.*;B. import java.applet.*;C. import java.awt.event.*;D. import java.io.*; 以下返回true的…

【从零开始学习JVM | 第一篇】快速了解JVM

前言&#xff1a; 在探索现代软件开发的丰富生态系统时&#xff0c;我们不可避免地会遇到一个强大而神秘的存在——Java虚拟机&#xff08;JVM&#xff09;。作为Java语言最核心的组成之一&#xff0c;JVM已经超越了其最初的设计目标&#xff0c;成为一个多语言的运行平台&…

JavaScript包管理器分类和区别

一、JavaScript包管理器分类 NPMYarnPNPMBun 二、包管理器的区别 1、NPM 是Node.js的默认包管理器&#xff0c;默认随Node.js一起安装&#xff0c;无需额外配置。 npm2 采用简单的递归依赖方法&#xff0c;最后形成高度嵌套的依赖树。然后就会造成如下问题&#xff1a;重复依…

【JavaSE】网络编程(学习笔记)

一、网络编程概述 网络编程&#xff1a;网络互联的计算机实现数据交换 1、网络编程三要素 1&#xff09;IP IP&#xff1a;网络中设备的唯一标识 cmd -> ipconfig&#xff1a;查看本机ip cmd -> ping ip地址&#xff1a;检查网络是否连通 127.0.0.1&#xff1a;回送地…

Ubuntu环境下使用nginx实现强制下载静态资源

安装Nginx sudo apt update sudo apt install nginx关闭防火墙 sudo ufw allow Nginx HTTP修改nginx配置 cd /etc/nginx/conf.d vi nginx.conf在http配置中添加(/your path/为需要下载的文件路径) server {listen 80;server_name localhost;location / {root /your path/…

convert_from_pinhole_camera_parameters 失败

函数convert_from_pinhole_camera_parameters 在0.17版本中有bug。 应该说是&#xff0c;直接使用pip install open3d 的0.17版本有问题&#xff0c;在git code中已经修复&#xff0c;需要下载后用pip安装。希望pip赶紧更新。。。。 参考&#xff1a; Fix the pybind refer…

WPS Office JS宏实现批量处理Word中的标题和正文的样式

该篇讲解下word文档中的标题和正文批量修改样式&#xff0c;如下图&#xff1a; 前面一篇已讲解了WPS Office宏编辑器操作方法&#xff0c;这里不细讲了&#xff0c;如有不清楚可以查看该篇&#xff1a;https://blog.csdn.net/jiciqiang/article/details/134653657?spm1001.20…

Install4J安装界面中如何使用脚本找到依赖程序XShell的安装位置

前言 写了一个工具, 使用Install4j打包, 但因为需要用到XShell, 所以希望在安装界面能够提前让用户配置好XShell的安装位置, 所以对Install4j的安装界面需要自定义, 后期在程序中直接过去安装位置就可以正常使用. 调研 和git-bash不一样, 安装版的XShell没有在注册表里存储安…

Ubuntu系统下使用apt-get安装Redis

记录一下Ubuntu20.04 64位系统下使用apt-get安装Redis 首先检查一下系统是否安装过redis whereis redismywmyw-K84HR:~$ whereis redis redis: mywmyw-K84HR:~$ 更新软件包 sudo apt-get update -y安装redis sudo apt-get install redis-server -ymywmyw-K84HR:~$ sudo apt…