我们有一个已经运行了几年的Delphi应用程序,现在我们突然发现了奇怪的访问冲突。我们使用Eurekalog来追踪它的来源,这更加奇怪。到目前为止,它们都是对象的Free调用,但是在try中除了块之外。其中一个甚至在2个尝试除了块之外仍然在发生访问冲突时它完全跳出程序并忽略了尝试例外,除了EurekaLog最后捕获它之外没有任何东西。真的很困惑为什么会突然发生这种情况(这两个实例都是多年未触及的旧代码,而且其他代码更改也与它无关)。
代码的一个例子是
try
if Assigned(ClientCommunication) then begin
if ClientCommunication.isConnected then begin
if ClientCommunication.closeServerConnection then begin
try
ClientCommunication.Free;
ClientCommunication := nil;
Except
on e:Exception do begin
ClientCommunication := nil; //suppress weird AV error.. get read for new object
end
end;
现在最后一次尝试除了稍后添加以尝试抑制AV,因为我们只是希望清除的对象在需要时重新启动,但这通常在关闭应用程序时调用。但它仍然只是跳出来,我根本无法抓住它。
它适用于我们的开发者PC而不是客户端。
答案 0 :(得分:1)
如果此行:ClientCommunication.Free;
导致异常。
你可以在这里做一些事情。
<强> FreeAndNil 强>
将来电AObject.free
的来电替换为freeandnil(AObject)
如果您只是执行自由,旧指针仍将具有非零引用,Assigned(AObject)
将无法区分释放和活动对象。
谨防克隆
你可能犯的另一个错误就是你像这样克隆了对象:
Object1:= TObject1.Create;
//.... lots of code
Object2:= Object1;
//.... lots of code
FreeAndNil(Object2); <<-- freeing the clone-reference is a mistake
//.... lots of code
Object1.Free; <<-- exception: it's already freed
FastMM4选项
从http://sourceforge.net/projects/fastmm/下载最新的FastMM4
它有一些额外的铃铛和口哨来自Delphi附带的。(*)
在这些口哨中有一个额外的诊断模式,它会使你的程序死得很慢,但也会发现你似乎正在遭受的许多堆腐败错误。
打开defines.inc
并更改此内容:
{$ifdef DEBUG}
{.$define EnableMemoryLeakReporting}
{.$define FullDebugMode}
{.$define RawStackTraces}
{$endif DEBUG}
进入这个
{$ifdef DEBUG}
{$define EnableMemoryLeakReporting}
{$define FullDebugMode}
{$define RawStackTraces}
{$define CatchUseOfFreedInterfaces} <<-- very useful
{$define LogMemoryLeakDetailToFile}
{$define LogErrorsToFile}
{$define CheckHeapForCorruption} <<-- :-)
{$endif}
这里有一篇很好的文章:http://wiert.me/2009/07/29/delphi-fastmm-using-fastmm4-for-debugging-your-memory-allocations-part-1-introduction/
如果您不喜欢使用inc文件,那么可以使用一个小工具:http://jedqc.blogspot.com/2007/07/new-fastmm4-options-interface.html
(*)我认为Delphi也有大部分调试内容,但不是100%肯定。无论如何都无法获得最新(最好)的版本。
或缓冲区溢出
如果您的ClientCommunication
对象具有一些免费的内部结构,则可以执行额外的工作。
想象一下以下代码:
TUnrelatedObject = class
buffer: array[0..99] of integer;
procedure DoWork;
end;
TUnrelatedObject.DoWork;
var
i: integer;
begin
for i:= 0 to 100 do buffer[i]:= maxint; <<-- buffer overrun
end;
想象一下,ClientCommunication
就在堆中的UnrelatedObject
旁边
对DoWork
的调用也会覆盖ClientCommunication
的数据
这可能会也可能不会触发DoWork中的访问冲突。如果没有,那么错误将很难追踪,因为它将出现在一个不同且完全不相关的地方。
在您的应用中启用范围检查{$R+}
。
警告强>
请记住不将调试版本发送给您的客户
通过所有调试,您的程序将会变慢。