如何在 Delphi 7 中跟踪某个类在内存中的计数,而不在类中添加静态计数成员。用于跟踪程序性能。提前谢谢你。
问问题
433 次
2 回答
4
您可以在 VMT 类中挂钩 NewInstance 和 FreeInstance 方法:
unit ClassHook;
{no$DEFINE SINGLE_THREAD}
interface
var
BitBtnInstanceCounter: integer;
implementation
uses Windows, Buttons;
function GetVirtualMethod(AClass: TClass; const VmtOffset: Integer): Pointer;
begin
Result := PPointer(Integer(AClass) + VmtOffset)^;
end;
procedure SetVirtualMethod(AClass: TClass; const VmtOffset: Integer; const Method: Pointer);
var
WrittenBytes: {$IF CompilerVersion>=23}SIZE_T{$ELSE}DWORD{$IFEND};
PatchAddress: PPointer;
begin
PatchAddress := Pointer(Integer(AClass) + VmtOffset);
WriteProcessMemory(GetCurrentProcess, PatchAddress, @Method, SizeOf(Method), WrittenBytes);
end;
{$IFOPT W+}{$DEFINE WARN}{$ENDIF}{$WARNINGS OFF} // avoid compiler "Symbol 'xxx' is deprecated" warning
const
vmtNewInstance = System.vmtNewInstance;
vmtFreeInstance = System.vmtFreeInstance;
{$IFDEF WARN}{$WARNINGS ON}{$ENDIF}
type
TNewInstanceFn = function(Self: TClass): TObject;
TFreeInstanceProc = procedure(Self: TObject);
var
OrgTBitBtn_NewInstance: TNewInstanceFn;
OrgTBitBtn_FreeInstance: TFreeInstanceProc;
function TBitBtn_NewInstance(Self: TClass): TObject;
begin
Result := OrgTBitBtn_NewInstance(Self);
{$IFDEF SINGLE_THREAD}
Inc(BitBtnInstanceCounter);
{$ELSE}
InterlockedIncrement(BitBtnInstanceCounter);
{$ENDIF}
end;
procedure TBitBtn_FreeInstance(Self: TObject);
begin
{$IFDEF SINGLE_THREAD}
Dec(BitBtnInstanceCounter);
{$ELSE}
InterlockedDecrement(BitBtnInstanceCounter);
{$ENDIF}
OrgTBitBtn_FreeInstance(Self);
end;
procedure InstallHooks;
begin
OrgTBitBtn_NewInstance := GetVirtualMethod(TBitBtn, vmtNewInstance);
OrgTBitBtn_FreeInstance := GetVirtualMethod(TBitBtn, vmtFreeInstance);
SetVirtualMethod(Buttons.TBitBtn, vmtNewInstance, @TBitBtn_NewInstance);
SetVirtualMethod(Buttons.TBitBtn, vmtFreeInstance, @TBitBtn_FreeInstance);
end;
procedure RemoveHooks;
begin
SetVirtualMethod(Buttons.TBitBtn, vmtNewInstance, @OrgTBitBtn_NewInstance);
SetVirtualMethod(Buttons.TBitBtn, vmtFreeInstance, @OrgTBitBtn_FreeInstance);
end;
initialization
InstallHooks;
finalization
RemoveHooks;
end.
将此单元包含在程序的任何子uses
句中,现在BitBtnInstanceCounter
将跟踪TBitBtn
实例数。
编辑:如果有可能多个线程同时创建被跟踪类的对象,则有必要使用互锁访问来修改计数器变量。请注意,第三方组件可能会静默使用线程,因此不定义SINGLE_THREAD
符号会更安全。
于 2012-05-10T21:56:50.460 回答
3
没有内置的方法可以做到这一点。一些分析器(AQTime?)通过安装自定义堆管理器挂钩然后查看位于任何对象开头的类型指针来为您生成此类指标。您可以自己执行此操作,但如果这是为了在开发期间进行分析,则仅使用其他人已经开发和测试的内容会容易得多。
于 2012-05-10T17:42:05.933 回答