📄 195.txt
字号:
虽然内存泄露一般出现在异常情况下,毕竟给系统造成很大的隐患,使系统的健壮性降低
。测试人员在作代码审查时,对上述几种情况要尤其注意。
【案例1.10.4】
【正 文】在进行SAR的PDU包发收的测试过程中要同时考虑几个边界值,即发送
包大小范围[0-Nmax],SAR的PDU包接收的最大值Kmax,MBUF块的大小M.在实测中,将SAR的PD
U包接收的最大值设为2000(Kmax=2000B), MBUF的块长设为512(M = 512B),则发送包大小的
正确分支的取值为下限0,上限Nmax=2000,然后在0与2000之间随机取若干值,再考虑MBUF的
块长,还可增加M倍数的若干选值及其附近值.以上是测试的一般思路,但由于很偶然的机会
选择包长2000,及Kmax=2000B,才发现问题.原因如下:
MBUF块长512,但块中实际存放数据的只有500(MBUF头上有2个长字,尾部有1个长字共12B只
用于块控制),而发送的包长正好是500的整数倍4,由于是整数倍,所以SAR(BT8230)从FREE链
上摘成5个MBUF(原因从略),而SAR驱动只知道有4个MBUF,这样到上层用户时,只释放4个MBU
F,从而漏掉1个MBUF,经过很短一段时间后,内存即被耗尽.(此问题非常严重,因为在实际运
用中,是500的整数倍的PDU包的概率较小,但一旦出现就会发生一次内存泄漏,这样经过若干
天或若干月的运行后会使系统崩溃)
以前未发现此问题的原因是因为原来使用的缓冲块长为2048,减去12B的控制信息,实际存放
数据的长度为2036.由于只考虑了2048这个值,忽略了2036,所以在选取上下限中的若干值时
,选取包的长度是2036的倍数的概率就非常小,因而未发现该问题.
由于测试中一般很难将取值范围中的所有值覆盖全,所以在选取上下限中的若干取值时要格
外仔细,考虑的方面尽可能全,因为很有可能其中某些值就是测试边界值.凡是涉及的数字尽
量选取,象该例中正确分支的测试边界为0,2000,512及其整数倍,500 及其整数倍,12 及其
整数倍等值,它们是必测的边界值,而非可测可不测的随机选取的所谓若干选值.
【案例1.10.5】
【正 文】
ABIS.CPP中的函数rel_ABIS_CCB_conn( )中,在进行消息链表Msg_Queue[ces]的拆链操作
时,对于相应的CCB只进行了一次拆链操作,即只拆除了一个节点,如果出现该CCB对应的
消息节点不止一个的情况就会出现大量节点不能释放的问题。
if( Msg_Queue[ces].msghead != NULL_PTR )//message buffer notempty
{
//get first message record
pMsgRecord = Msg_Queue[ces].msghead;
//release buffer-messages concerning with ccb_no
for( index = 0; index < MSGBUFFERNUM; index++ )
{
//这里要对pMsgRecord的值进行判断
if( (pMsgRecord != NULL_PTR) && pMsgRecord->CCB_no ==
ccb_no )
{
//free the message buffer
if( pMsgRecord == Msg_Queue[ces].msghead )//head
Msg_Queue[ces].msghead = pMsgRecord->pnext;
else if( pMsgRecord == Msg_Queue[ces].msgtail )//tail
{
Msg_Queue[ces].msgtail = pPrevMsgRecord;
Msg_Queue[ces].msgtail->pnext = NULL_PTR;
}
else//not head and tail
{
pPrevMsgRecord->pnext = pMsgRecord->pnext;
}
//put buffer back to buffer pool
if( Msg_Buffer.empty_num == 0 )
{
Msg_Buffer.linkhead = Msg_Buffer.linktail = pMsgRecord;
pMsgRecord->pnext = NULL_PTR;//这里将
pMsgRecord->pnext置为空
Msg_Buffer.empty_num++;
}
else
{
Msg_Buffer.linktail->pnext = pMsgRecord;
pMsgRecord->pnext = NULL_PTR;//这里将
pMsgRecord->pnext置为空
Msg_Buffer.linktail = pMsgRecord;
Msg_Buffer.empty_num++;
}
}
else if( pMsgRecord == NULL_PTR )
break;//end of if
//get next message record
pPrevMsgRecord = pMsgRecord;
pMsgRecord = pMsgRecord->pnext;//这时pMsgRecord为
NULL_PT
R将跳出for循环语句
}//end of for
}//end of if
这里在拆除一个节点后导致pMsgRecord为NULL_PTR,再进行判断时将会跳出循环,这样将
不能保证所有与同一个CCB有关的节点均被拆除,这时如果与同一个CCB对应的消息节点不
止一个则这些消息节点均无法释放,造成可用的节点数不断减少,直接影响系统的建链过
程,给系统的稳定带来隐患。
后与开发人员联系,根据这段算法编写小程序验证了该问题,并提出了相应的解决方案,
消除了该隐患。
【案例1.10.6】
【正 文】
1、建立一个呼叫,并保持通话。在AM控存监控操作界面中观察通话建立在哪一块
FBI板上。
2、将有通话的FBI板拔出,观察通话情况,此时话音中断,但信令仍然保持。观察
AM控存监控操作界面和E3M板2K网界面,发现AM侧因为检测到光纤已断,将通话在CTN、E3
M板上占用的时隙置为空闲,即在AM控存监控操作界面和E3M板2K网界面观察不到时隙占用
情况。
3、分别在30秒、1分钟、3分钟时将拔出的FBI板插回原槽位,发现每次插回FBI板后
话音立即恢复。
4、观察BAM上的打印消息,发现打印的各模块占用CTN板大HW上DM时隙的空闲个数比
较混乱。打印消息如下图所示:
其中:
1) 由于模块1、2、3、4各占用CTN板上两条大HW,每个DM时隙个数为256(即由两条
大HW的两个DM组成,由于与OPT相联的大HW上有两个保留时隙,因此此DM上空闲时隙个数为
:254。
2) 由于E3M板只与一条大HW相联,故每个DM上空闲的时隙个数为:128。
本现象对应2个问题:idle_count打印混乱,BM释放故障光路的时隙和对应的CCB、无
线信道等资源。
1、idle_count打印混乱是由于函数restore_one_hw中的一些处理不当造成的,以前被当作
B型机的历史遗留问题没有重视;
2、B2模块有2条光路,如果断掉其中一条,模块状态不会改变,原B型机程序对此不作任何
处理,但应该增加这个功能,以免光路故障导致资源吊死。
解决方法:
问题一: 将函数restore_one_hw中原代码作如下改动:
mod_dm[mod][i].tail.tsn = idle_dm_head + 125;
( idle_dm_head == 384 ) ?
mod_dm[mod][i].idle_count += TS_PER_DM - 1:
mod_dm[mod][i].idle_count += TS_PER_DM - 1;
改为:
if ( idle_dm_head != 384 )
{
mod_dm[mod][i].tail.tsn = idle_dm_head + 127;
mod_dm[mod][i].idle_count += TS_PER_DM;
}
else
{
mod_dm[mod][i].tail.tsn = idle_dm_head + 126;
mod_dm[mod][i].idle_count += TS_PER_DM - 1;
}
问题二分析如下:
目前的模块状态是由IPATH调用DBMS模块的边检查实现的,只要存在一条可用
的光路,即认为相邻模块为正常,对于具体的OPT板上的时隙状态的维护没有与呼叫控制的
接口。具体的OPT板状态功能的检测是由IPATH完成的,在BM侧没有专门维护OPT和MC2板的
模块,将转交OS组处理。
总结:
在拔出FBC板后,通话话音被中断,AM/CM侧已将与被拔出的FBC 板相关的资源
全部置为不可用,此时BM侧主机程序也应该与AM/CM侧一致,释放掉所占用的资源,并将原
通话的信令连接断开。这可能是由于不同模块的开发人员缺少相互间了解而造成的,即AM
/CM侧与BM侧开发人员交流不够。作为测试人员对类似两个或多个模块相关的部分应该充分
进行测试,不要想当然,往往是看起来不可能出问题的地方也容易测出问题。
【案例1.10.7】
在进行有关排队指示的系统测试中,先闭塞掉基站的所有业务信道TCH,进行呼叫,再直
接挂机或超时释放,发现TC存在中继资源吊死的问题。
由于此问题重现,后经定位分析,发现是ccb超时后收到AIR发来的clear cmd,进入 rel
_one_bm_res( )时,由于ccb所登记的CIC还放在pre_occupied_res,并没有放入occuped_
res,而rel_one_bm_res()只对存入occuped_res的CIC进行判断,并向AIE发UNBOOKCIC,而
没有对存入pre_occupied_res的CIC进行判断,并UNBOOK掉,导致TC的中继资源吊死。应在
超时函数或释放函数中对pre_occupied_res的CIC进行处理。
在此过程中,CIC资源还存放在老CCB的pre_occupied_res中,在超时函数或释放函数中均
未对pre_occupied_res中的CIC进行处理(即向AIE UNBOOK),导致TC中继资源吊死。
在超时函数RR_time_out()中timer_name为TN_WAIT_ASS_READY时,和释放函数rel_one_b
am_res()中增加对CCB的pre_occupied_res中的CIC的判断和释放处理。
在使用资源同时,就要周密地考虑好资源的释放问题,只有这样,才能使我们的
系统不断地稳定下来。
资源的释放对于我们的交换机来说是至关重要的,一点点的疏忽都可能最终使我们的交
换机因为无资源使用而死掉,要知道,“千里长堤,毁于蚁穴”。
11、防止资源的重复释放
【案例1.11.1】
【正 文】
当进行大话务量呼叫时,在统计代码中出现AIE收到UNBOOK CIC消息时,发现自身
电路状态为空闲,出现一个断言。这说明AIE电路电路被误释放了。
这个问题出现的原因有以下几种:
1. RR可能发错了电路号,导致AIE状态错误。
2. AIE可能发起资源核查,失败后将本控制表项释放了。
3. RR可能发起了重复释放操作,导致AIE的某个表项连续收到两个UNBOOK消息。
分析完了可能的情况,就要一一分析定位。
在可能原因一发生的情况下,RR发来的UNBOOK消息所带的AIR连接号和模块号会错误,导
致我们会出现断言。而在测试数据结果文件中,没有出现这个断言,因此可能原因一不成
立。
在可能原因二发生的情况下,AIE收到资源核查失败消息的数目应该不是零。但是实际情
况下统计结果中收到资源核查失败消息的个数为零,说明情况二也不成立。
由上分析,这个问题只可能是由于RR重复释放造成的。但是为何会发生重复释放,这需要
进行进一步分析。
从呼叫的正常流程来看,是不会产生重复释放的,因此我们怀疑该问题与异常流程有关。
从统计代码中查找异常流程,发现该次统计中BSC内切换流程多次出现问题,具体原因是由
于切换过程中在目标小区申请不到信道,产生切换失败造成的。因此集中研究这个流程,
发现存在问题如下:
当原小区向目标小区发送内部切换请求消息时,带来了AIR和AIE的各项信息,而目标小区
收到这些信息后就将之保存在自身的占用资源中。如果目标侧申请信道失败,就会向源侧
发内部切换拒绝消息,而后产生本地释放。由于在释放前目标侧RR没有将占用资源中的AI
R和AIE信息清除,因此导致重复释放时对AIR和AIE发起了释放操作。由于AIR释放时有保护
机制,所以不会产生问题,而AIE没有保护机制,新CCB就将AIE电路释放掉了。而后当老C
CB在通话结束后发起释放时,就产生了重复释放。
从上面分析可以看出,这个问题是由于RR释放流程的错误造成的,因此,我们要对此加以
修改,在新CCB释放前将AIR和AIE信息从预占资源中清除。
RR的释放是一个非常复杂的过程,如何正确的整理资源,确保资源的合理释放,
这是摆在我们面前的一个艰巨的问题,我们要仔细分析各种可能发生的情况,正确释放各
种资源,即不会吊死资源,也不会产生重复释放。
12、公共资源的互斥性和竞用性
【案例1.12.1】
【正 文】
试验环境:CPX8216 CPCI 机架、vxWorks操作系统、Tornado1.0.1调试环境
测试用例:测试板间通信性能。从接口板A向接口板B循环发送消息,通过超级终端观察消
息的收发情况。
测试结果:每发送一定数量的消息帧后,会出现发送地址出错现象。
原因分析:接收板回送缓冲区指针给发送板,是采用memcpy单字节拷贝的方式。若发送速
度快于接收速度,两板竞用发送板系统总线访问缓冲区指针所在的共享内存,导致数据访
问冲突。memcpy过程被打断,即出现发送板读发送地址出错现象。
采用四字节拷贝函数bcopyLongs传送发送缓冲区指针,问题解决。
共享内存的访问设计,除了考虑互斥外,还有总线竞用问题。
【案例1.12.2】
【正 文】
问题描述:
在进行主BCCH载频互助新功能开发的并行联调测试的过程中,发现了以下的问题
:在数管台设置“TRX倒换是否允许”为“是”,进行设定整表后,关闭基站其中配有4个
TRX的小区的主BCCH所在的TRX电源,发现对应小区重新初始化并成功,也就是载频互助成
功。这个时候从后台对该小区所在的站点进行4级复位,同时重新打开之前关闭的该小区的
原配主BCCH所在TRX的电源,发现对应小
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -