1.以前版本的CnMemProf在打开了记录到文件选项之后会误报一个内存漏洞
2.以前版本的CnMemProf由于使用了TypInfo,所以误报的可能性很大,现在版本默认是不是用TypInfo单元的,可以使用编译器指示字打开。
3.由于D6本身的品质问题,CnMemProf会存在一定的误报,我印象中打上了SP1的D6要好一些,可是上次发现打了所有不定的D6误报明显(在2没有使用之前)
下面是有关的一些邮件的讨论:
今日一朋友zhujj报告了CnMemProof中的一个奇怪问题,说D7环境下一个空工程创建后,只要uses 了DB单元,即使无任何其他操作,程序退出的时候就报错说有1处内存泄漏。经测试果然有这个问题,下面是工程文件代码:
用最简单的测MemProof:
program Project1;
uses
CnMemProf in 'CnMemProf.pas',
DB;
begin
end.
然后和Shenloqi兄讨论,基本上能确定下来这是引用了TypInfo单元所导致的问题,结论就一句话:Borland的问题,我们没有法子,^_^
类似的问题在D5中还未测试出来(可能不存在),在D6中似乎更加严重。后来商量着解决方案是设置一编译开关控制是否记录RTTI信息,默认不打开。——在准确度和详细度之间,只有选择前者了。
相关任务单:
http://www.cnvcl.org:8008/cnpack/tktview?tn=70
另外,在讨论过程中也谈到了异常处理的一些问题。Passion平时的感觉是,try except end是关键字,是编译器内部定义的,能映射到windows的SEH结构化异常处理,不需要库文件支持。但今天和Shenloqi兄讨论后才知道,SysUtils单元的initialization处的InitExceptions实际上有莫大的作用,如果一个单元的代码先于SysUtils的初始化部分执行,那么里头的try except等将不能捕获错误,原因就是因为ExceptProc 未能被设置成 @ExceptHandler 所致,导致异常无法处理。
>Delphi6 中创建一个新的应用程序都会有 8 个漏洞( 什么控件和代码都没写),您知道是什么回事吗?忘了说,Delphi6 打了所有的补丁。
我以前曾经在Delphi 5/Delphi 6/Delphi 7中测试过,并没有发现这个问题,最近我的一个硬盘坏了,所以现在我的机器上只有Delphi 5,经过测试不存在这个问题,以前也有一个朋友给我写信说空的Delphi 6的工程有七八个(我不记得是七个还是八个了)漏洞,可是他发过来的单元确是忘记把CnMemProf作为DPR的uses的第一个单元了,所以希望您检查一下,如果的确就是有泄漏,请将源代码给我一份。
>最后发现 CnMemProf 单元有个 Bug ,当使用了 mmErrLogFile 后,会出现内存漏洞,改为 mmErrLogFile: string[255] = ''就行了。
感谢您报告这个BUG,不过这其实是一个假象,是误报而不是真正的内存泄漏。Delphi对字符串的管理是自动引用计数的。作为全局变量mmErrLogFile: string = '';跟mmErrLogFile: string;并没有不一样,这么写的目的仅仅是为了防止将来的编辑器有什么变化,而mmErrLogFile: string[255] = '';跟前面的写法有本质的差别,也应该是您的这种写法。
您既然知道改正这个BUG,肯定是知道这个BUG产生的原因的了,这里我说出我的理解,希望和您讨论一下:
在新内存管理器生效之前,mmErrLogFile指向的是引用计数为0的常量(如果是mmErrLogFile: string = ''指向的地址是$00000000,如果是mmErrLogFile: string = 'xxx'则指向的是一个字符串常量,该常量在内存中的实际值是:FFFFFFFF 03000000 78787800),因为该单元是工程的第一个单元,所以对mmErrLogFile的赋值肯定发生在新内存管理器生效之后的,这时候由于Delphi对string是写复制的,所以设定这个变量就向新内存管理器申请了空间,且因为有全局的mmErrLogFile引用该区域,而全局变量的生存区间是大于新内存管理器生效的区间的,所以在新内存管理器失效之前该字符串的引用计数始终大于0(这时候内存中的实际值是:01000000 03000000 78787800,这01的引用就是mmErrLogFile了),也就是说字符串不能在新内存管理器移交之前及时释放,因此造成了只申请未释放的假象,因而就产生了误报。