我的程序在运行一段时间后会自动关闭。所以我利用CheckMemory检测到7 处内存漏洞,详细信息如下: 可用地址空间 : 1024 KB(1048576 Byte)
未提交部分 : 864 KB(884736 Byte)
已提交部分 : 160 KB(163840 Byte)
空闲部分 : 142 KB(145680 Byte)
已分配部分 : 15 KB(16136 Byte)
全部小空闲内存块 : 11 KB(11836 Byte)
全部大空闲内存块 : 130 KB(133844 Byte)
其它未用内存块 : 0 KB(0 Byte)
内存管理器消耗 : 1 KB(2024 Byte)
地址空间载入 : 1%当前出现 7 处内存漏洞 :
0) 0000000001864AE0 - 23($0017)字节 - 不是对象
1) 0000000001864AF4 - 22($0016)字节 - 不是对象
2) 0000000001873818 - 119($0077)字节 - 不是对象
3) 0000000001873F90 - 23($0017)字节 - 不是对象
4) 000000000187C86C - 23($0017)字节 - 不是对象
5) 0000000001876688 - 119($0077)字节 - 不是对象
6) 000000000187BFC8 - 19($0013)字节 - 不是对象
7) 00000000018852A0 - 31($001F)字节 - 不是对象
8) 0000000001873E90 - 23($0017)字节 - 不是对象
9) 0000000001873EA4 - 22($0016)字节 - (未命名): TMetafile (48 字节) - In Graphics.pas
10) 0000000001873EB8 - 22($0016)字节 - 不是对象
11) 000000000188A55C - 39($0027)字节 - 不是对象
12) 000000000188CD64 - 311($0137)字节 - 不是对象
13) 0000000001888314 - 23($0017)字节 - 不是对象
14) 000000000188FF6C - 87($0057)字节 - 不是对象
15) 0000000001889A90 - 15($000F)字节 - 不是对象
16) 00000000018853B0 - 19($0013)字节 - 不是对象
17) 000000000188FFC0 - 42($002A)字节 - 不是对象
18) 000000000188E75C - 23($0017)字节 - 不是对象
19) 000000000188E770 - 22($0016)字节 - 不是对象
20) 000000000186B560 - 19($0013)字节 - 不是对象*******************************
那我怎么在程序中找出这七个地方来呢。。想了关天,就没有想出来。再次麻烦大家了。
未提交部分 : 864 KB(884736 Byte)
已提交部分 : 160 KB(163840 Byte)
空闲部分 : 142 KB(145680 Byte)
已分配部分 : 15 KB(16136 Byte)
全部小空闲内存块 : 11 KB(11836 Byte)
全部大空闲内存块 : 130 KB(133844 Byte)
其它未用内存块 : 0 KB(0 Byte)
内存管理器消耗 : 1 KB(2024 Byte)
地址空间载入 : 1%当前出现 7 处内存漏洞 :
0) 0000000001864AE0 - 23($0017)字节 - 不是对象
1) 0000000001864AF4 - 22($0016)字节 - 不是对象
2) 0000000001873818 - 119($0077)字节 - 不是对象
3) 0000000001873F90 - 23($0017)字节 - 不是对象
4) 000000000187C86C - 23($0017)字节 - 不是对象
5) 0000000001876688 - 119($0077)字节 - 不是对象
6) 000000000187BFC8 - 19($0013)字节 - 不是对象
7) 00000000018852A0 - 31($001F)字节 - 不是对象
8) 0000000001873E90 - 23($0017)字节 - 不是对象
9) 0000000001873EA4 - 22($0016)字节 - (未命名): TMetafile (48 字节) - In Graphics.pas
10) 0000000001873EB8 - 22($0016)字节 - 不是对象
11) 000000000188A55C - 39($0027)字节 - 不是对象
12) 000000000188CD64 - 311($0137)字节 - 不是对象
13) 0000000001888314 - 23($0017)字节 - 不是对象
14) 000000000188FF6C - 87($0057)字节 - 不是对象
15) 0000000001889A90 - 15($000F)字节 - 不是对象
16) 00000000018853B0 - 19($0013)字节 - 不是对象
17) 000000000188FFC0 - 42($002A)字节 - 不是对象
18) 000000000188E75C - 23($0017)字节 - 不是对象
19) 000000000188E770 - 22($0016)字节 - 不是对象
20) 000000000186B560 - 19($0013)字节 - 不是对象*******************************
那我怎么在程序中找出这七个地方来呢。。想了关天,就没有想出来。再次麻烦大家了。
解决方案 »
- 如何写这样的Panel 控件?
- 多线程传递参数问题
- 编辑DBGridEh1后如何刷新统计值呢?
- [研究]delphi数据库连接与内存分配的效率问题(大家提点建议)
- 用RAVE做出来的报表,要打印其中的几张为什么打印不了?
- 关于listbox的操作,请帮忙看一下,在线等
- 还有一个问题,在运行的时候怎么改变控件(label,image等)的大小呢?
- 初学者关于socket的一系列问题
- 如何拷贝一个树的节点,及其下属节点,到另一个TreeView的一个节点中呢?
- 在ClientDataset中删除最后一条记录时出Invalid variant type conversion,怎么解决?
- 关于线程池的问题
- 定时长取数
===================
能不能把原来的blog就指向现在的 偶尔去看了一下原来的地址:www.matrix.org.cn/blog/magicgod ,竟然还在,可是已经没有办法维护了,上面是一大堆广告评论,严重损害我的形象 :-) 。反正原来的文章这里都有,建议干脆地址转换一下好了,免得还有不知情的人继续访问旧的内容。
由{0}发表于 magicgod ( 2006年04月06日, 11:04:54 上午 CST ) Permalink 留言 [2]
www.kicoy.com
由{0}发表于 magicgod ( 2006年04月03日, 02:42:24 上午 CST ) Permalink 留言 [0]
星期六 2006年04月01日
使用FastMM4结合View CPU避免内存泄漏 关键字:FastMM, Delphi, 内存泄漏, View CPU。
阅读前提: 有Delphi基础,关注本地代码和内存管理。内存泄漏经常出现在本地代码中,特别是多线程和发生异常的情况下,这时候在delphi环境下,FastMM4就特别有用。FastMM4是非常高效可靠的内存管理器,用来替代久久不更新的borland内存管理器是最好的。地址:http://sourceforge.net/projects/fastmm/调试过程如下:1.打开FastMM4的调试功能,首先在自己的project里把FastMM4放在最前面,例如: FastMM4,
Main in ‘Main.pas’ {MainForm},
再修改FastMM4Options.inc,打开全调试模式。例:{$define FullDebugMode}也可以在project中定义编译常量:FullDebugMode。同时把FastMM_FullDebugMode.dll拷贝到编译后生成的可执行程序所在目录。再要打开内存泄漏报告:EnableMemoryLeakReporting。一般情况下是缺省打开的。这样就打开了全调试模式,如果发生内存泄漏将会生成报告文件,如果在IDE运行的时候还会弹出一个对话框显示。报告文件类似:kicoy_MemoryManager_EventLog.txt2.报告文件由两部分组成,并且是每次运行append。第一部分是泄漏的详细内容,将每个没释放的内存块详细信息显示出来。例:A memory block has been leaked. The size is: 28 {一个28字节的内存块在程序结束后没有被释放}{这个内存块在分配的时候的调用堆栈,也就是Call Stack,可以清楚看出调用函数的次序。如果是系统dll则还有相应的函数名。}
Stack trace of when this block was allocated (return addresses):
4028E7
4030EC
406649
412365
41236E
411DD3
426B45
427236
42888C
{这个内存类型,如果是字符串string或TObject继承的对象则会显示名称。}
The block is currently used for an object of class: Unknown{将内存块头256个字符显示出现,作为内容提示。}
Current memory dump of 256 bytes starting at pointer address 107BDD8:第二部分是总结性内容,例:{这个小型内存块泄漏的报告,如果有大型内存块泄漏则会加一行专门提示大型内存块泄漏。}
This application has leaked memory. The small block leaks are (excluding expected leaks registered by pointer):{21-28字节的内存块泄漏,未知类型一个}
21 - 28 bytes: Unknown x 1Note: Memory leak detail is logged to a text file in the same folder as this application. To disable this memory leak check, undefine “EnableMemoryLeakReporting”.有了这份报告只不过了解到内存泄漏存在,但是哪里没释放就还需要更进一步地调查。调查的目标有:1.内存块分配在哪个函数里哪段代码。这个在报告里可以结合内容和调用堆栈来看。前256个字节可以进行分析,推测分配者,调用堆栈就直接指出了分配函数,不过是一些地址,不能直接知道函数名和代码段。这时候就需要在delphi ide环境下查看二进制内存映像了,就是View CPU功能。在设定断点并停下后,可以View CPU,在菜单View=>Debug Window=>CPU 快捷键:Ctrl+Alt+CView CPU Window:正中就是内存映像,而且源码也相应地标注好了,左边列的地址就是内存报告中的Call Stack中的地址,翻页找到所对应的代码就知道哪里分配内存了。2.检查释放内存的地方是否被调用,可以用日志或断点来调试,如果压根就没有释放内存那就补上代码,如果有却没有执行则检查一下执行条件是否正确,如果断点没起作用很可能是因为代码永远不会被执行(死代码)。这要靠经验和调试,基本上借助IDE和内存报告就可以很好地防止内存泄漏。同时要加强测试用例,争取在测试用例中能遍历到所有的代码和大部分关键功能,这样内存泄漏报告就会更准确一点。fastmm每次在程序关闭后就会根据情况生成内存泄漏报告,如果没有弹出内存泄漏警告则恭喜你,内存管得很好。现在总算不用羡慕虚拟机代码自动回收内存了,本地代码的内存管理也不是两眼一抹黑了,这是可以精确控制的,一切尽在掌握中。另:1.内存管理不是GC自动回收内存,而是检查是否有泄漏。2.windows系统的内存泄漏是无法检查的,仅限于应用程序内部,不过检查出系统泄漏也没办法,只能等更新了。3.检查泄漏后要自己去检查代码补齐内存释放,报告并不能做这事。——
A memory block has been leaked. The size is: 20Stack trace of when this block was allocated (return addresses):
402A97
4F3069
4043AB
7C816D4FThe block is currently used for an object of class: UnknownCurrent memory dump of 256 bytes starting at pointer address 1161290:
01 00 00 00 0B 00 00 00 43 6F 6D 6D 61 6E 64 54 65 78 74 00 D0 ED E9 FE 00 00 00 00 B1 0F 16 01
00 00 00 00 00 00 00 00 00 00 00 00 97 2A 40 00 45 6C 50 00 AB 43 40 00 4F 6D 81 7C 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 B7 2A 40 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 10 00 00 00 00 00 00 00 B0 12 16 01
D8 98 56 00 80 80 80 80 80 80 80 80 80 80 80 80 4F ED E9 FE 80 80 80 80 00 00 00 00 B1 12 16 01
00 00 00 00 00 00 00 00 00 00 00 00 97 2A 40 00 55 6C 50 00 AB 43 40 00 4F 6D 81 7C 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 B7 2A 40 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 10 00 00 00 00 00 00 00 30 13 16 01(The FastMM_DebugInfo.dll library is not available, so no unit/line number debug information can be displayed in the stack traces.)--------------------------------2006/7/11 10:54:45--------------------------------
A memory block has been leaked. The size is: 44Stack trace of when this block was allocated (return addresses):
402A97
40DD4F
55A4E8
404344
4043AB
7C816D4FThe block is currently used for an object of class: UnknownCurrent memory dump of 256 bytes starting at pointer address 117A1B0:
01 00 00 00 1E 00 00 00 5C 53 6F 66 74 77 61 72 65 5C 4D 61 69 6E 53 65 6E 64 5C 63 68 65 6E 67
7A 68 6F 6E 67 5C 00 00 B0 5E E8 FE 80 80 80 80 00 00 00 00 19 A3 17 01 00 00 00 00 00 00 00 00
00 00 00 00 97 2A 40 00 DA FF 49 00 8B 00 4A 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 B7 2A 40 00 2E E5 49 00 06 E2 49 00 C1 B3 42 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 29 00 00 00 00 00 00 00 E8 A1 17 01 D8 98 56 00 80 80 80 80
80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80
80 17 5E E8 FE 80 80 80 00 00 00 00 E9 A1 17 01 00 00 00 00 00 00 00 00 00 00 00 00 97 2A 40 00
DA FF 49 00 8B 00 4A 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00(The FastMM_DebugInfo.dll library is not available, so no unit/line number debug information can be displayed in the stack traces.)--------------------------------2006/7/11 10:54:45--------------------------------
This application has leaked memory. The small block leaks are:5 - 12 bytes: Unknown x 4
13 - 20 bytes: String x 2, Unknown x 2
37 - 44 bytes: String x 1
也就是在你的程序的二进制映象中找到所给出的256字节的内容.
找出后,在CPU VIEW中也有你的源代码,你就可以找出到底是哪里了.另外,FASTMM给出的Stack是你的程序出现泄露时的堆栈情况
Current memory dump of 256 bytes starting at pointer address 117A1B0:
中的117A1b0这个地址,是你的泄露的变量刚分配完成后中的CPU的CX宿存器的内容.
对于二进制映象中的256个字节的内容和堆栈的内容,我试过好多次,可以是方法不对,就是不知道它们怎么找出来.
5 - 12 bytes: Unknown x 4
13 - 20 bytes: String x 2, Unknown x 2
37 - 44 bytes: String x 1
上面的这个报告说你有4个未知类型的泄露,大小是5-12字节,然后是2个String的内存泄露,应该是泄露的这部分内容存储的是String类型的数据.
=========
在不知道怎么利用binary Image 和 Call Stack的内容之前,你的这个错误我是不知道找出来,太不好找了.
=============
你可以先做一个简单的程序来测试一下,熟悉一下它怎么用.例如,做一个按钮,在单击的事件中创建一个TObject对象,但故意不释放它.
procedure TForm1.Button1Click(Sender: TObject);
var
a: TObject;
begin
a:= TObject.Create; // set the break point
end;
然后你就可以在报告中发现:--------------------------------2006/8/1 13:07:26--------------------------------
A memory block has been leaked. The size is: 4Stack trace of when this block was allocated (return addresses):
402E8A
43E06E
429BFD
43E1A4
43E06E
44DCEE
43D7F7
41EA12
77D015DFThe block is currently used for an object of class: TObjectCurrent memory dump of 256 bytes starting at pointer address A2C480:
EC 10 40 00 E0 3B 5D FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00(The FastMM_DebugInfo.dll library is not available, so no unit/line number debug information can be displayed in the stack traces.)--------------------------------2006/8/1 13:07:26--------------------------------
This application has leaked memory. The small block leaks are:1 - 4 bytes: TObject x 1
这是说有一个TObject的对象泄露,大小是1-4字节,实际上是4字节,但是实际上这个是对象的指针的大小.
好,然后,再在 TObject.Create的地方设置好断点,拦下后,调出CPU VIEW, 看到汇编代码
Unit1.pas.30: a:= TObject.Create;
00453344 B201 mov dl,$01
00453346 A1A0104000 mov eax,[$004010a0]
0045334B E8B804FBFF call TObject.Create //注意这行
Unit1.pas.31: end;
00453350 C3 ret 单步执行到Call TObject.Create这一行,并执行完,你会发现CX的内容就是你在报告中的A2C480
也就是说,只要你找到了A2C480这个地址,你就可以找到TObject.Create,你就可以知道是这里分配的内容出现了泄露=====
这样虽麻烦,但是也是找到出要找的地方,因为我暂不知道如何得用Binary Image和Call Stack中的数据,只好用笨办法了.实际上,我用这样的笨办法找出到我的许多错误.
===
再有一点,上面虽报告了三次的错误,但实际上,很有可能那是你的一行代码造成的泄露,只要修复了那个泄露,就可以使相关的泄露消失
祝你成功,如果你得到了其它的经验,别忘了发贴上来共享:)
.