fu.wei 的个人资料傅威的创意生活照片日志列表 工具 帮助
8月12日

Flex内存泄露问题

最近弄数据仓库的元数据,这工作里面的一项重头戏就是解析SQL语句。由于数据仓库的数据加工逻辑比较复杂,成百上千行的SQL随处可见,因此如何把其中的数据来源与去向清晰的整理出来是非常重要的,以前我解析SQL语句用C++自己写,能实现部分功能,这次用的工具是Flex和Bison,学过编译原理的都知道大名鼎鼎的Lex/yacc这两个工具,Flex和Bison就是Lex/yacc的windows版本,Flex是解析词法的,Bison是用来解析语法的。
我写了一个Flex的例子测试,这个例子能把SQL语句群按照分号隔开,放入一个list,并且读出每一句SQL的起始和结束的位置,以及该SQL的类型,例如是一个空SQL还是只含注释的SQL,还是一个标准SQL。Flex这个工具生成读入后缀是l的词法文件,然后输出一个lex.yy.c的文件,我写了个程序测试这个lex.yy.c。我的目标是把这个解析器做成MFC DLL或者能输出xml的标准程序,这样以后的元数据项目就能直接用了,甚至能通过GUI界面处理SQL,但是Flex生成的.c文件MFC程序无法直接使用,首先要注释掉c文件中的#include <unistd.h>这一行,这行会报错,再修改b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;这一行,让b->yy_is_interactive = 0,然后在把.c文件的的开头的#include <stdio.h>替换成#include <stdafx.h>,这样就行了么?还不行,VC2003编译还是报错,我鼓捣半天才发现,需要把lex.yy.c文件重命名成lex.yy.cpp就可以了,这一系列操作太复杂了,我写了一个批处理文件生成cpp,然后又写了一个VC的宏来修改文件,这样,按两下鼠标一切就都OK了,嘿嘿,懒人就喜欢自动化。
然后写了简单的界面输入SQL进行解析,解析效果不错,但是运行后却发现了两处内存泄露,一处是16386字节,一处是40字节。在这里先给非程序员普及一下内存泄露的知识,任何一个计算机程序,在运行的时候存放数据是需要内存的,需要多少内存是程序向操作系统申请的,这块内存用完了就把它还给操作系统,操作系统可以再分配给其他程序。就像我们去饭馆吃饭,饭菜就是数据,内存就是碗和碟子,我们点了菜又点汤,这时候碗不够了,我们就会喊一声:“老板,再拿两个碗来盛汤”,这就是内存申请,等我们吃完了抹嘴买单走人,服务员收拾碟子和碗,这就是内存回收,如果我们看到这家饭馆的碗太漂亮了,于是偷偷拿走一个(这事我经常干),这就是内存泄露。如果偷碗的人太多了,这家饭馆的碗就不够了,你再申请要碗老板就会说碗不够了,请稍等一下,于是你们几个人只能用一个碗吃饭,吃的很慢,这就叫内存不足。C++和C的程序太灵活了,请求碗和送回碗都是程序员自己来做,就像一个饭馆没人看管,完全靠个人自觉性来维持,因此不管是水平差也好,疏忽也好,C/C++程序会很容易产生内存泄露,java和C#就好多了,他们就相当于饭馆门口有搜身的,你一个碗也带不走。
这里我发现了两处内存泄露,一共16KB左右,你可能会说才16KB,现在内存都好几个GB,这么点算什么,但是如果这是一个服务器上常年不停机运行的程序,有很多人来访问,会很快把内存吃掉的。虽然我这个程序不是服务器上运行的程序,但是我能容忍程序的bug,却不能容忍内存泄露,想当年我刚刚写C++程序的时候,程序有内存泄露,我死活找不出来是哪里的问题,最后只能告诉客户说我这个程序要求内存多,你的电脑需要增加内存,于是客户增加了内存,但即使这样也不行,还需要半夜重启一下机器才可以。在此我对该客户表示深深的歉意,从此我发誓,再也不让我的程序有一个字节的内存泄露,于是深山苦练coding和调试技术,经过多年的浸淫,自己写的代码肯定不会有这样的错误了,而且别人的多复杂的问题代码我拿过来就调试,就跟饭端过来就吃一样easy。
这回的问题我认为很easy,调试呗,一开始以为是list有问题,这是很容易出问题的地方,CList是一个模板类,用了好多年了,好用量又足,我们一直用它,但是CList里面如果放入指针的话就要注意了,简单的Removeall是不行的,还需要一个一个的delete掉里面的对象指针,我跟踪了一遍,不是它的问题,每次内存泄露的大小都是那么多,与list的大小没关系。难道是我写的CSQLSet和CSQLNode这两个类有问题?仔细查了一遍也没问题,奇了怪了,难道是lex.yy.c不能和MFC混在一起用,我有把这个程序拆出来,用纯c做了一遍,果然没报告内存泄露,好像是问题解决了。但是我如果简单的在程序里面用MFC CString类,就会报告泄露,CString这更是久经考验的共产主义战士,不可能有问题的,太令人困惑了,后来通过艰苦的内存检查发现,其实纯c的程序也有内存泄露!只不过VC2003没有报告罢了,这简直是VC的一个大bug!这太让我失望了,以前用VC6我比较喜欢numega的调试插件,它能发现比较隐秘的bug和泄露,但是VC2003我觉得应该不错了,就没去找这样的插件,没想到啊没想到,微软还是忽悠了我一下。
现在问题就集中在Flex生成的lex.yy.c上了,这个程序很长,好几千行,而且作者肯定是C的高手,很多地方没看懂,太牛了,我从头到尾大概浏览一遍,里面好几处申请了内存,可能就是它们的问题,但是这程序太复杂了无法下手啊,郁闷之中上网google,输入Flex memory leak,结果发现了Adobe有一个产品也叫Flex,而且也有内存泄露问题,我倒,什么世道啊,我又加入关键字lex.yy.c,这回搜出来的对了,原来不止一个人发现了这个问题,很多人都在报告这个问题,但是讨论都没结果,找到Flex的老家sourceforge.net,打算投诉一下作者,看到上面有讨论,又搜索了一下,作者针对内存泄露的问题说了,对于制作解析非C的解析器来说,可能会有泄露问题,解决的方案是在你真的准备结束解析的时候加上这两句代码:
yy_delete_buffer(YY_CURRENT_BUFFER);
yy_init = 1;
我加上了,好了,困扰我两天的问题解决了,这下世界清静了。但是看到其他的帖子说Bison也会有内存泄露,前面的路还很长。
8月10日

奥你ma的运

上网瞎逛,发现一首摇滚歌曲,是一个叫山西晋国盘古乐队创作的,叫做《奥你ma的运》, 歌词很简单,很朴素,几乎就是两句话“cao你ma的北京,奥你ma的运”,这首歌现在已经被查封了,据说还要严惩,乐队成员不知道什么下场。
有人说这首歌很糙,一点旋律也没有,一点内涵也没有,但我说它有一样东西就足够了,那就是属于摇滚的反叛精神,这种精神让我当年痴迷摇滚(甚至也留起过辫子),可惜如今找不到这种感觉了,当年的摇滚群星据说要开演唱会迎接奥运了。
我不是反对奥运,我想这个盘古乐队也不是对奥运有仇,但是当奥运被政治化,当体育运动被包养起来,当所有的媒体都在连篇累牍的填鸭一样给民众灌输奥运,千言万语隧化作一句掷地有声的话:“奥你ma的运”。
鉴于国情,我就不在这里放这首歌的链接了,大家有兴趣可以去google一下,youtube上有视频。
顺便提一句,搜索这首歌的时候又发现了一个香港的歌曲叫《福佳始終有你》,这首歌讽刺的比较深刻一些,旋律也好听,呵呵,谁说香港人没文化。
 
8月4日

怎么搞的,哪里有问题啊

今天上海下雨,晚上7:00雨停了,我出去跑步,雨后比较凉爽,跑了21公里,一个半程的马拉松,用了2小时10分钟,比去年参赛还多10分钟,跑完感觉体力有点不支,可是这离全程还差一半啊,我能否跑下全程呢?最近一周跑的量加大了,次数也加了,但是每天称体重,还是150斤,有时候还是152,一斤都减不下来,怎么搞的,急死我了,我已经严格控制饮食了,早上一片面包一杯奶(低糖的奶),中午一荤一素(菜我全用汤涮过,没有油),晚上不吃饭也不吃水果了,只啃黄瓜和胡萝卜,隔一天还跑个10几公里,我现在简直是自虐啊,可是好像呼吸空气和饮水就能给我提供能量似的。
按照科学计算:
我每天的基础代谢是1800大卡左右,跑16公里消耗1160大卡左右,共2960大卡,如果想瘦下来,必须摄取少于这个热量才行,还得至少少一半才行。
去年体重减的很快,一个诀窍就是游泳,游泳消耗的热量比跑步多一倍还要多,游一个半小时,相当于跑三个小时,很快体重就到140了,可惜上海金桥这里竟然没有标准的游泳馆,有几个小区的游泳池,去过一次,全是25米的短池,不分道,一帮孩子在里面扑腾,水很脏,我看见有人在水里醒鼻涕,价格还比北京贵一倍,好怀念东单游泳馆、铁道文化馆游泳馆、奥体中心的游泳馆啊,按理说上海这边这么多水,市政府这么有钱,哪怕建个露天的游泳池呢。
既然游不了泳,只能跑步了,从下周开始,自虐升级,中午饭菜再减半,晚上再多跑!