当前位置: 首页 > news >正文

数据结构---双向链表(内存泄露相关知识)

一、内存泄露

内存泄露(Memory Leak)是指程序中已动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。内存泄漏是程序设计中常见的错误之一,其特点包括隐蔽性和积累性。

一、内存泄露的定义

       内存泄漏并非指内存在物理上的消失,而是指应用程序分配某段内存后,由于设计错误或疏忽,失去了对该段内存的控制,使得该内存无法被再次使用或回收,从而造成了内存的浪费。

二、内存泄露的原因

1. 资源未被正确释放:程序中动态分配的内存(如使用malloc、new等函数分配的内存)在不再使用时,必须显式地释放(如使用free、delete等函数)。如果忘记释放或者释放时机不当,就会导致内存泄漏。

2. 垃圾回收机制失效:在一些使用垃圾回收机制的语言中(如Java、Python等),如果垃圾回收器未能及时回收无用的内存对象,也可能导致内存泄漏。这通常是由于程序中存在对无用对象的引用,使得垃圾回收器无法识别并回收这些对象。

3. 循环引用:在对象间存在循环引用的情况下,即使这些对象已经不再被程序的其他部分使用,它们也可能因为相互引用而无法被垃圾回收器回收,从而导致内存泄漏。

4. 程序设计错误:如错误的算法设计、错误的内存分配策略等,都可能导致内存泄漏。

 三、内存泄露的影响

内存泄漏会导致系统可用内存逐渐减少,进而影响程序的运行速度和稳定性。在极端情况下,内存泄漏甚至可能导致系统崩溃或无法响应。此外,内存泄漏还可能引发安全问题,如敏感信息泄露等。

四、如何避免内存泄漏

为了避免内存泄漏,开发人员可以采取以下措施:

1. 合理设计程序:在程序设计阶段就考虑到内存管理的问题,采用合适的算法和数据结构来减少内存的使用和泄漏。

2. 及时释放内存:在程序中及时释放不再使用的内存资源,避免内存泄漏的发生。

3. 使用内存检测工具:利用专业的内存检测工具来检测和分析程序中的内存泄漏问题,及时修复潜在的内存泄漏点。如使用valgrind工具

4. 编写高质量的代码:通过代码审查、单元测试等方式来提高代码质量,减少因程序设计错误导致的内存泄漏问题。

二、双向链表

双向链表(Doubly Linked List)是一种数据结构,它与单向链表相似,但每个节点不仅包含指向下一个节点的指针,还包含指向上一个节点的指针。

双向链表的每个节点通常包含以下两个指针:

  • prev:指向上一个节点
  • next:指向下一个节点

通过这两个指针,可以在双向链表中沿着两个方向遍历。

相比于单向链表,双向链表能够更方便地进行插入和删除操作。因为每个节点包含指向前一个节点的指针,所以在删除或插入一个节点时,只需要修改该节点前后节点的指针即可。而在单向链表中,则需要在删除或插入节点时,找到该节点的前一个节点,以便进行指针修改,显得相对麻烦。

//头插
int push_doulink_head(DLink_t *pdoulink, DataType data)
{DLink_Node_t *pnode = malloc(sizeof(DLink_Node_t));if(NULL == pnode){perror("fail malloc");return -1;}pnode->data = data;pnode->ppre = NULL;pnode->pnext = NULL;if(is_empty_doulink(pdoulink)){pdoulink->phead = pnode;}else{pnode->pnext = pdoulink->phead;pdoulink->phead->ppre = pnode;pdoulink->phead = pnode;}pdoulink->clen++;return 0;
}
//遍历
void push_printlist(DLink_t *pdoulink, int dir)
{if(is_empty_doulink(pdoulink)){return;}DLink_Node_t *p = pdoulink->phead;if(dir){while(p != NULL){printf("%d ", p->data.id);printf("%s ", p->data.name);printf("%d \n", p->data.score);p = p->pnext;}}else{while(p->pnext != NULL){p = p->pnext;}while(p != NULL){printf("%d ", p->data.id);printf("%s ", p->data.name);printf("%d \n", p->data.score);p = p->ppre;}}
}
//尾插
int push_doulink_end(DLink_t *pdoulink, DataType data)
{if(is_empty_doulink(pdoulink)){push_doulink_head(pdoulink, data);}else{DLink_Node_t *p = pdoulink->phead;DLink_Node_t *pnode = malloc(sizeof(DLink_Node_t));if(NULL == pnode){perror("fail malloc");return -1;}pnode->data = data;pnode->ppre = NULL;pnode->pnext = NULL;while(p->pnext != NULL){p = p->pnext;}p->pnext = pnode;pnode->pnext = NULL;pnode->ppre = p;pdoulink->clen++;}
}

 使用头删时,需要注意当只有一个节点的情况,对于双向链表而言,p->pnext为空,此时p->pnext->ppre不存在,无法置为空,会发生栈崩溃。

//头删
int push_doulink_headpop(DLink_t *pdoulink)
{if(is_empty_doulink(pdoulink)){return 0;}DLink_Node_t *p = pdoulink->phead;pdoulink->phead = p->pnext;if(p->pnext != NULL){p->pnext->ppre = NULL;}free(p);pdoulink->clen--;return 1;
}
//尾删
int push_doulink_endpop(DLink_t *pdoulink)
{if(is_empty_doulink(pdoulink)){return 0;}DLink_Node_t *p = pdoulink->phead;if(p->pnext == NULL){push_doulink_headpop(pdoulink);}else{while(p->pnext != NULL){p =p->pnext;}p->ppre->pnext = NULL;free(p);pdoulink->clen--;return 1;}
}

 使用完要及时销毁,避免内存泄露,可使用valgrind ./a.out查看是否发生内存泄露。

//销毁
void destroy_pdoulink(DLink_t *pdoulink)
{while(!(is_empty_doulink(pdoulink))){push_doulink_headpop(pdoulink);}free(pdoulink);}

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 机器学习 第8章 集成学习
  • consul配置ACL安全认证
  • 又一款强大好用的Shell脚本项目,支持Bash,Sh、Dash、Ksh等,甚至可以在编辑器中直接用,程序员必备!(附源码)
  • AIGC大模型扩图:Sanster/IOPaint(4)
  • CyclicBarrier CountDownLatch
  • CSS 基础
  • 15.2 定义一个prometheus数据存储使用的pv
  • 若依Ruoyi之智能售货机运营管理系统(新增运营运维工单管理)
  • 第151天:红队APT-钓鱼篇邮件钓鱼SPF绕过自建邮件系统SwaksGophish
  • 如何让Google收录我的网站?
  • Docker 部署 Redis (图文并茂超详细)
  • 如何通俗易懂的解释TON的智能合约
  • HarmonyOS开发5.0【应用程序包】
  • webctf
  • 【机器学习-监督学习】集成学习与梯度提升决策树
  • .pyc 想到的一些问题
  • 77. Combinations
  • Angular2开发踩坑系列-生产环境编译
  • es6
  • Git 使用集
  • HTML中设置input等文本框为不可操作
  • HTTP中GET与POST的区别 99%的错误认识
  • iOS 系统授权开发
  • iOS小技巧之UIImagePickerController实现头像选择
  • Java 11 发布计划来了,已确定 3个 新特性!!
  • JavaScript设计模式之工厂模式
  • PAT A1050
  • weex踩坑之旅第一弹 ~ 搭建具有入口文件的weex脚手架
  • 阿里中间件开源组件:Sentinel 0.2.0正式发布
  • 从零开始的无人驾驶 1
  • 前端路由实现-history
  • 前嗅ForeSpider中数据浏览界面介绍
  • 如何选择开源的机器学习框架?
  • 体验javascript之美-第五课 匿名函数自执行和闭包是一回事儿吗?
  • 我的zsh配置, 2019最新方案
  • ​虚拟化系列介绍(十)
  • (14)Hive调优——合并小文件
  • (70min)字节暑假实习二面(已挂)
  • (SERIES12)DM性能优化
  • (博弈 sg入门)kiki's game -- hdu -- 2147
  • (附源码)计算机毕业设计SSM保险客户管理系统
  • (七)Flink Watermark
  • (一)Docker基本介绍
  • (转)Google的Objective-C编码规范
  • (转)Mysql的优化设置
  • .bat批处理(四):路径相关%cd%和%~dp0的区别
  • .NET Core 中插件式开发实现
  • .NET 给NuGet包添加Readme
  • .NET 药厂业务系统 CPU爆高分析
  • .Net环境下的缓存技术介绍
  • ??Nginx实现会话保持_Nginx会话保持与Redis的结合_Nginx实现四层负载均衡
  • [ Algorithm ] N次方算法 N Square 动态规划解决
  • [ HTML + CSS + Javascript ] 复盘尝试制作 2048 小游戏时遇到的问题
  • [ACTF2020 新生赛]Include
  • [android]-如何在向服务器发送request时附加已保存的cookie数据