如何修复链表集合中Valgrind检测到的内存泄漏问题
问题分析与修复方案
内存泄漏的根本原因
你遇到的内存泄漏非常典型:你的链表集合只实现了节点分配(Ajouter),但没有对应的内存回收机制,而且测试程序在每次循环中重复初始化集合,却从未释放上一次循环中分配的节点内存。
具体来说:
- 每次
Essais循环(共100次),你调用Initialiser(Ensemble),但这个操作只是把Ensemble设为Null,并没有释放之前Ajouter分配的所有节点。 - 每次测试会添加11个节点(10到20共11个整数),100次测试就产生了1100个节点,这些内存在程序结束时都没有被释放,正好对应Valgrind检测到的1100块丢失内存。
修复步骤
1. 给集合包添加内存销毁过程
首先在Ensembles_Chainage包中实现一个Detruire过程,负责迭代释放链表中所有节点的内存。
修改linked_set.adb(即你的Ensembles_Chainage包体),添加以下过程:
procedure Detruire (Ensemble : in out T_Ensemble) is Temp, Suivant : T_Ensemble; begin Temp := Ensemble; while Temp /= Null loop Suivant := Temp.all.Suivant; -- 先保存下一个节点的引用,避免释放后丢失 Free(Temp); -- 释放当前节点的内存 Temp := Suivant; end loop; Ensemble := Null; -- 将集合重置为空状态 end Detruire;
同时要在包的规范文件(.ads)中声明这个过程,确保外部可以调用:
procedure Detruire (Ensemble : in out T_Ensemble);
2. 在测试程序中调用销毁过程
修改测试程序nombre_moyen_tirages_chainage.adb的循环逻辑,在每次测试循环结束后调用Detruire释放本次测试分配的所有节点内存:
for i in 1..Essais loop Initialiser (Ensemble); -- 初始化空集合 loop Get_Random_Number(n_alea); -- 获取随机数 Moyenne := Moyenne + 1; -- 累加抽取次数 if not(Est_Present (Ensemble, n_alea)) then ajouter (Ensemble, n_alea); -- 将随机数添加到集合 end if; exit when Taille (Ensemble) = Max - Min + 1; end loop; Detruire(Ensemble); -- 释放本次测试中分配的所有节点内存 end loop;
验证修复效果
重新编译程序后用Valgrind检测,你会看到definitely lost和indirectly lost的内存数值都变为0,内存泄漏问题完全解决。
额外建议
- 养成Ada中分配即回收的习惯,对于动态分配的内存,一定要提供对应的释放机制,避免资源泄漏。
- 可以优化
Initialiser过程,在初始化前先调用Detruire,这样即使外部忘记手动释放,也能避免内存泄漏。
内容的提问来源于stack exchange,提问作者user11110733
相关产品推荐
相关产品推荐

