望普陀而路远,去罗浮以何及!朝受命,夕饮冰,燃灯不熄!

后羿系统VM-Agent模块内存泄露问题抽丝剥茧

上一篇 / 下一篇  2009-11-16 12:10:00 / 个人分类:语言

先来说一下VM-Agent(gcc开发)从原型到当前版本的架构变化:51Testing软件测试网%JE"XS1D)r#^9h

原型阶段:VM-Agent有一个进程与后羿控制系统(erlang实现)的NC进行通讯,根据NC传达的请求,进行VM的调度。51Testing软件测试网mLV9O~%M Tx

当前阶段,把VM-Agent的通讯过程全部交给控制系统的NC本身进行处理,VM-Agent以命令行程序的形式供NC调用。

jRp{!?A8O~/kF4t0

这样的好处在我看来有三个:

i#lx~wA4Z ]0

1、  从架构上看更合理,所有通讯相关的处理都由控制系统接管。51Testing软件测试网4}*_$JbA2e

2、  降低了C程序员的开发难度,现在可以把更多的精力放在对VM本身的研究与处理上。

'G'e3R#U.`#v dv0

3、  在原有架构上则可能出现《高质量C/C++编程指南》说的:“含有内存错误的函数每被调用一次就丢失一块内存。刚开始时系统的内存充足,你看不到错误。终有一次程序突然死掉,系统出现提示:内存耗尽。”,我估计这也可能是开发人员改变架构的原因之一吧;但现在采用命令行方式,就算有内存泄露出现,命令行结束,进程退出,所有分配的内存也将被操作系统收回。51Testing软件测试网*sd.p ZM:F!W

那么可能有人要问,既然已经用命令行了,那还管什么内存泄露呢,让它露吧,无所谓,是这样的吗?请仔细看《高质量c/c++编程指南》第7.6章,这一段经典的例子,正是VM-Agent发生内存泄露的相同原因:51Testing软件测试网;z-@jh r0lR

~Q~'[%G_)PL)R0

好了,现在进行正题,看看我是如何抽丝剥茧,定位VM-Agent的内存泄露的:

f/s"hkZr0

一、环境:51Testing软件测试网r3Lb"Ko

Linux+gcc+VIM+ctag+ valgrind

n1YnF"_T0

二、简要描述一下测试用例51Testing软件测试网IHGj)s1\

调用VM-Agent的./vmcli –methodname=startVm……命令(后面更多参数略),启动(创建一个)虚拟机

T.g/}G T$x K0

两个用例:A.虚拟机已经启动后执行启动命令,启动失败。B.此虚拟机没有启动时执行启动命令,启动成功,可以用xm list查看,也可ssh直接登陆这个新启动的虚拟机,也可以直接看命令返回值。

a{ uX;COX ^0

三、过程

.o\i2X|0

当这两个用例分别都执行成功后,我对其分别进行了一个内存泄露的检测:51Testing软件测试网1`E E4aM:i%I)lC9n%U

1、  valgrind ./vmcli–………(启动VM失败的用例),结果报告:51Testing软件测试网 S*a,IPQb'l:|X

 

;[V\+IQ0

可见,没有什么问题,非常正常。51Testing软件测试网N1F"Dzb~^y u

2、  valgrind ./vmcli–………(成功启动VM的用例),结果报告:51Testing软件测试网dL*] @9K^op

51Testing软件测试网Fz'H3R"z/g3CO

 

9S)@!i%sh m\Iw0

从上面的红字可以看到更简单的定位方法,一开始没注意到这一句只看上面两句关键的了,真是折腾了我半天,不过也用手工追踪的方式找到了(在VIM下用ctag会帮助你在程序中实现跳转)。51Testing软件测试网)rf@0Uvm,hp0J)^

好,现在假装我们都没看到红字部份,继续追踪,从main一直ta到关键代码中,直接到这段代码中看:

z[*B CM2f0

 51Testing软件测试网'T nX2}:dLF;iR0u

                                  51Testing软件测试网v u8BQQP8OmCb}

继续ta到get_instance_xml_file中,发现只有两个静态的数据,使用了snprintf方式给值,很安全嘛,也没有动态内存的分配,不过 ,这个东东引起了我的注意,看看用在什么地方的:

B3M"h Onbt+[0

 51Testing软件测试网(Q"tA6J]

而这个char ** xml是从这里申明的,正是main->do_run…->get_instance…->replace_string这个可疑的家伙,ta进去看看吧:

%\W s3X BOV0

 51Testing软件测试网9Lsc!z}r;Gu\

怎么样,看出什么来了没?是不是和《高质量c/c++编程指南》7.6中的例子惊人的相似?51Testing软件测试网#?-i:UAs

上图也说明了为什么replace_string被调用了多次,最后只有一块2048内存泄露的原因!51Testing软件测试网z.V N:` V5q#f

 51Testing软件测试网 a+cjR#B

好,现在我们再用valgrind –leak-check=full ./vmcli –methodname=startVm….来看看结果:51Testing软件测试网Nt)L{1t!{*?%E

        

vV-t/|)P6f&_w"u:H-Q^0

         最后被定位到replace_string,在代码中的第56行,正是动态分配了内存的那一行,唉,早加上这个参数,我就不用这么折腾了!:(

9?+F_w5`@0

         至于valgrind为什么能做到这种定位,从上面也可看出,是它的桩函数的作用,这项强大的功能,我们也完全可以自己实现,用它来做单元测试,你甚至不需要Cunit这样的工具都行,当然有Cunit还是要用的,不折腾嘛。51Testing软件测试网-\imJR6kQ~

 

xBLv"b|8uI0

四、总结51Testing软件测试网%J4GimYf5Q

写C语言的规范问题,内存应该是谁使用谁申请,谁申请,谁释放,从VM-Agent代码可以看出程序员当时的思路:do_run_instance申明了char *xml,但do_run_instance没有申请内存,当然不用释放,当这个char*xml经过三个函数的不断中转到了最后一个replace_string函数时,replace_string也不能释放,因为调用者还要使用呢,你要释放了,人家用什么,哈哈,真是杯具呀。这段代码让我想起一个笑话(如果你没笑,就当我讲的是故事):51Testing软件测试网 k]A\0P azJo

有一哥儿们叫了一碗豆浆(价值1元),伙计把豆浆给他后,他说他不要了,把豆浆换成两根油条(两根也是1元),这哥儿们吃完后不付钱就要走,伙计说:“你吃的油条还没给钱呢”,他说:“油条是我用豆浆换的,为什么要给钱?”,伙计说:“可是豆浆你也没给钱呀?”,这哥们一甩手说:“我又没喝豆浆,为什么要给钱?”,然后扬长而去!。。。。,于是内存泄露就此发生了,杯具!

#zG!d,?Z_djLE%l0

TAG: 虚拟机 valgrind VM 内存泄露

 

评分:0

我来说两句

Open Toolbar