[英]How to test whether a object is freed in Delphi
The two programs as shown below try to test whether a object is freed, using the techniques described here Bad reference to an object already freed . 如下所示,这两个程序尝试使用此处介绍的技术测试对象是否被释放。 错误引用已经释放的对象 。
The first program as shown below runs correctly if compiled under Delphi 7, but wrongly if compiled under Delphi XE and upper. 如果在Delphi 7下编译,则如下所示的第一个程序可以正确运行,而在Delphi XE及更高版本下,则编译不正确。 That is to say, it outputs
也就是说,它输出
D7 DXE
True True
True True
True False
True True
False True
False False
program Project1;
{$APPTYPE CONSOLE}
uses
SysUtils;
function ValidateObj(Obj: TObject): Pointer;
// see { Virtual method table entries } in System.pas
begin
Result := Obj;
if Assigned(Result) then
try
if Pointer(PPointer(Obj)^) <> Pointer(Pointer(Cardinal(PPointer(Obj)^) + Cardinal(vmtSelfPtr))^) then
// object not valid anymore
Result := nil;
except
Result := nil;
end;
end;
function ValidateObj2(Obj: TObject): Pointer;
type
PPVmt = ^PVmt;
PVmt = ^TVmt;
TVmt = record
SelfPtr : TClass;
Other : array[0..17] of pointer;
end;
var
Vmt: PVmt;
begin
Result := Obj;
if Assigned(Result) then
try
Vmt := PVmt(Obj.ClassType);
Dec(Vmt);
if Obj.ClassType <> Vmt.SelfPtr then
Result := nil;
except
Result := nil;
end;
end;
var
Obj: TObject;
begin
Obj := TObject.Create;
Writeln(BoolToStr(Assigned(Obj), True));
Writeln(BoolToStr(Assigned(ValidateObj(Obj)), True));
Writeln(BoolToStr(Assigned(ValidateObj2(Obj)), True));
Obj.free;
Writeln(BoolToStr(Assigned(Obj), True));
Writeln(BoolToStr(Assigned(ValidateObj(Obj)), True));
Writeln(BoolToStr(Assigned(ValidateObj2(Obj)), True));
Readln;
end.
The second program, explicitly using FastMM4, as shown below runs wrongly when compiled under Delphi 7 or XE and upper. 在Delphi 7或XE及更高版本下编译时,第二个程序显式使用FastMM4,如下所示运行错误。 That is to say, it outputs
也就是说,它输出
Expected D7 DXE
False False False
True True True
True True True
True True False
True False False
True True True
False True True
False True False
program Project2;
{$APPTYPE CONSOLE}
uses
FastMM4,
SysUtils;
function ValidateObj(Obj: TObject): Pointer;
// see { Virtual method table entries } in System.pas
begin
Result := Obj;
if Assigned(Result) then
try
if Pointer(PPointer(Obj)^) <> Pointer(Pointer(Cardinal(PPointer(Obj)^) + Cardinal(vmtSelfPtr))^) then
// object not valid anymore
Result := nil;
except
Result := nil;
end;
end;
function ValidateObj2(Obj: TObject): Pointer;
type
PPVmt = ^PVmt;
PVmt = ^TVmt;
TVmt = record
SelfPtr : TClass;
Other : array[0..17] of pointer;
end;
var
Vmt: PVmt;
begin
Result := Obj;
if Assigned(Result) then
try
Vmt := PVmt(Obj.ClassType);
Dec(Vmt);
if Obj.ClassType <> Vmt.SelfPtr then
Result := nil;
except
Result := nil;
end;
end;
var
Obj: TObject;
begin
Obj := TObject.Create;
Writeln(BoolToStr(Obj is FastMM4.TFreedObject, True));
Writeln(BoolToStr(Assigned(Obj), True));
Writeln(BoolToStr(Assigned(ValidateObj(Obj)), True));
Writeln(BoolToStr(Assigned(ValidateObj2(Obj)), True));
Obj.free;
Writeln(BoolToStr(Obj is FastMM4.TFreedObject, True));
Writeln(BoolToStr(Assigned(Obj), True));
Writeln(BoolToStr(Assigned(ValidateObj(Obj)), True));
Writeln(BoolToStr(Assigned(ValidateObj2(Obj)), True));
Readln;
end.
I am confused how the wrong behavior is caused, and wonder how to test whether a object is freed for Delphi 7 and Delphi XE and upper, especially when FastMM4 is used ? 我很困惑如何导致错误的行为,并且想知道如何测试是否为Delphi 7和Delphi XE及更高版本释放了对象,尤其是当使用FastMM4时?
In general, it is not possible to make a robust test that a pointer refers to an instance that has been freed or not. 通常,不可能对指针指向已释放或未释放的实例进行可靠的测试。 It is the job of the programmer to maintain control of the lifetime of your objects.
程序员的任务是保持对对象生命周期的控制。
There is no way to check whether the object is valid, but to compare its pointer to NIL. 无法检查对象是否有效,只能将其指针与NIL进行比较。 Disallow objects to have more than one pointer, otherwise if this object freed by one pointer, reference to the same object on the second pointer will cause Access Violation.
禁止对象有一个以上的指针,否则,如果该对象由一个指针,参照在第二指针相同的对象释放将导致访问冲突。
you can test a VCL object if it is freed/freeing or not with the following code: 您可以使用以下代码测试VCL对象是否已释放/释放:
if (csFreeNotification in Self.ComponentState)
or (csDestroying in Self.ComponentState) then ... //Self is Freed or Freeing.
But you can not apply this method to ordinary pointers (non-VCL objects) 但是您不能将此方法应用于普通指针(非VCL对象)
I had problems with this too, but I got around it by doing the following 我也有这个问题,但我通过以下操作解决了这个问题
First create a new variable directly under interface 首先直接在界面下创建一个新变量
unit Login_Sys;
interface
var
bisnotinmemory:boolean=true;
Then go to the class you would like to randomly check to see if its still in memory's constructor and destructor methods and do something like this 然后转到您要随机检查的类,以查看其是否仍在内存的构造函数和析构函数方法中,并执行类似的操作
constructor TUserlogin.create;
begin
bisnotinmemory:=False;
and 和
destructor TUserlogin.free;
begin
bisnotinmemory:=true;
If you have to keep track of multiple object then you could always make the "bisnotinmemory" variable I used into an array. 如果必须跟踪多个对象,则可以始终将我使用的“ bisnotinmemory”变量放入数组中。
unit Login_Sys;
interface
var
bisnotinmemory: array[0..1] of Boolean = (true, true);
Just remember to add something like "iOBjectID : integer" to the create methode of the class like say 只要记住要在类的create方法中添加“ iOBjectID:integer”之类的内容,例如:
constructor TUserlogin.create(iOBjectID : integer);
begin
bisnotinmemory[iOBjectID]:=false;
iPersonalID:=iOBjectID;
You could even declare a variable like "iPersonalID" under the "private" area of the object for use when the destructor method gets called. 您甚至可以在对象的“私有”区域下声明一个变量,例如“ iPersonalID”,以便在调用析构函数方法时使用。
destructor TUserlogin.free;
begin
bisnotinmemory[iPersonalID]:=true;
I tested this with Delphi 2010 我用Delphi 2010测试了
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.