2012-05-10 3 views
1

클래스에 정적 계산 멤버를 추가하지 않고도 Delphi 7에서 메모리의 특정 클래스 수를 어떻게 추적 할 수 있습니까? 프로그램 성능을 추적하기위한 것입니다. 진보 된 감사합니다.델파이에 특정 클래스가있는 인스턴스의 수를 어떻게 추적 할 수 있습니까?

+0

클래스에 자체 생성자 및 소멸자가 있고 충분히 길면 코드를 조사하여 다른 곳에서 계산할 수 있습니다. madCodeHook (http://madshi.net)은이를 수행 할 수있는 잘 알려진 라이브러리입니다. –

+0

@WarrenP : 아마도 소스가 없거나 소스를 변경하고 싶지 않은 구성 요소이기 때문에 가능합니다. –

+2

예. 방금 그렇게 생각 했어. 성능면에서 단 하나의 대답 만 있으면됩니다. AQTIME을 구입하십시오. 잔인하게 비싼, 예. 그것에 붙어있는 HASP 라이센스 허튼 소리의 불쾌한 비트. 예. 그럼에도 불구하고 멋진 도구. –

답변

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 절 단위 지금 BitBtnInstanceCounterTBitBtn 인스턴스의 수를 추적합니다를 포함합니다.

편집 : 여러 스레드가 추적 된 클래스의 개체를 동시에 만들 수있는 경우 카운터 변수를 수정하려면 연동 액세스를 사용해야합니다. 타사 구성 요소가 스레드를 자동으로 사용할 수 있으므로, SINGLE_THREAD 심볼을 정의하지 않는 것이 안전합니다.

3

기본 제공 방법이 없습니다. 일부 프로파일 러 (AQTime?)는 사용자 정의 힙 관리자 훅을 설치 한 다음 오브젝트 시작 부분에있는 유형 포인터를 조사하여 이러한 메트릭을 생성합니다. 이 작업은 직접 수행 할 수 있지만 개발 중에 프로파일 링을 수행하는 경우 이미 다른 사람이 개발하고 테스트 한 것을 사용하는 것이 훨씬 쉽습니다.

관련 문제