在Delphi7中获取对象的分配地址
我有以下代码序列:在Delphi7中获取对象的分配地址,delphi,delphi-7,Delphi,Delphi 7,我有以下代码序列: program OverrideAfterConstructionEtc; {$APPTYPE CONSOLE} uses SysUtils, Classes; type TA = class( TInterfacedObject) public procedure AfterConstruction; override; procedure BeforeDestruction; override; protected FDummyData: array[ 1 .
program OverrideAfterConstructionEtc;
{$APPTYPE CONSOLE}
uses
SysUtils, Classes;
type
TA = class( TInterfacedObject)
public
procedure AfterConstruction; override;
procedure BeforeDestruction; override;
protected
FDummyData: array[ 1 .. 1000 ] of longint;
end;
{ TA }
procedure TA.AfterConstruction;
var
selfPtr: Pointer;
selfInt: Integer;
selfStr: string;
size: Integer;
begin
inherited AfterConstruction;
selfPtr := Addr( self );
selfInt := Integer( selfPtr );
selfStr := IntToHex( selfInt, 8 );
size := TA.InstanceSize;
WriteLn( 'TA instance allocated at 0x', selfStr );
WriteLn( 'TA size is ', size );
end;
procedure TA.BeforeDestruction;
var
selfPtr: Pointer;
selfInt: Integer;
selfStr: string;
size: Integer;
begin
selfPtr := Addr( self );
selfInt := Integer( selfPtr );
selfStr := IntToHex( selfInt, 8 );
WriteLn( 'Preparing to destroy TA instance allocated at 0x', selfStr );
size := TA.InstanceSize;
WriteLn( 'TA size is ', size );
inherited BeforeDestruction;
end;
const
maxDummy = 1000;
var
a: TA;
dummy: TList;
iter : integer;
dummies: array [ 1 .. maxDummy ] of TList;
begin
// Simulate a set of allocations.
for iter := 1 to maxDummy do
begin
dummy := TList.Create;
dummies[ iter ] := dummy;
end;
// Allocate the object we want to track.
a := TA.Create;
// Release the simulated allocations.
for iter := 1 to maxDummy do
begin
dummy := dummies[ iter ];
dummies[ iter ] := nil;
FreeAndNil( dummy );
end;
// Release the tracked object.
FreeAndNil( a );
end.
代码的输出为:
- 在0x0012FF88分配的TA实例
- TA的大小是4012,准备销毁
- 在0x0012FF80分配的TA实例
- TA的尺寸是4012
我不理解“自我”的区别。你能给我一个提示吗?我希望打印的值是相同的。以下代码将为您提供解释:
type
TA = class( TInterfacedObject)
public
procedure AfterConstruction; override;
procedure BeforeDestruction; override;
end;
procedure TA.AfterConstruction;
begin
inherited;
writeln('AfterConstruction=',integer(self));
writeln('AfterConstruction=',integer(addr(self)));
end;
procedure TA.BeforeDestruction;
begin
writeln('BeforeDestruction=',integer(self));
writeln('BeforeDestruction=',integer(addr(self)));
inherited;
end;
以下是输出:
AfterConstruction=10731904
AfterConstruction=1245020
BeforeDestruction=10731904
BeforeDestruction=1245028
所以整数(self)是正确的(两个值都等于10731904),但整数(addr(self))不是
因为addr(self)不显示self值,而是显示self值的存储位置
在这两种情况下,它都存储在堆栈中(使用Alt-F2分解这两种方法的前缀):
因此,当您使用addr(self)时,您查看的是当前堆栈地址,而不是self值
Addr不是指向指针的简单类型转换,但与@self相同,因此使用integer(self)与integer(Addr(self))不同
不应使用Addr(self)而应使用self来查找对象的分配地址。
self
在实例方法中是一个隐式参数,是对接收方法调用的实例的引用。它是作为指针实现的
Addr
标准程序与@
操作员相同;它获取传递给它的位置的地址。当您将Addr
应用于Self
时,您将获得参数位置的地址,而不是实例的地址。此参数位置在堆栈上分配,因为它只需要在方法调用处于活动状态时存在;当方法调用返回时,不再需要Self
参数的空间;CPU的堆栈指针移回调用该方法之前的位置,从而隐式释放该方法
Self
参数可能位于同一实例上不同方法调用中的不同位置的原因是,调用时堆栈上可能有更多或更少的数据。例如,如果方法调用序列看起来像A->B->C
而不是A->C
,则Self
参数的分配将不同,因为B
的堆栈帧需要存储在A
和C
的堆栈帧之间。堆栈框架是分配与方法的任何给定调用相关联的参数和局部变量的地方。谢谢您的回答。我如何将它们都标记为答案(web UI只允许我选择其中一个)?@Dan我想你只能选择一个!就这么定了!:)
mov [esp],eax