I just scribbled something together that should be good enough to start with and get some basic information about how many objects are created at a given time - needs to be first or directly after the memory manager unit in the dpr:
Replace the dictionary with a Spring4D one and you have some easy sorting and filtering on top 🙂
unit ObjectCounter;
interface
uses
Generics.Collections;
function GetObjectCounts: TDictionary<TClass,Integer>;
implementation
uses
madCodeHook;
type
TObjectCounter = record
class var ObjectCounts: TDictionary<TClass,Integer>;
class var OldInitInstance: function (Self: TClass; Instance: Pointer): TObject;
class var OldCleanupInstance: procedure (Self: TObject);
class function InitInstance(Self: TClass; Instance: Pointer): TObject; static;
class procedure CleanupInstance(Self: TObject); static;
class procedure Init; static;
class procedure Finalize; static;
end;
function GetObjectCounts: TDictionary<TClass,Integer>;
begin
Result := TObjectCounter.ObjectCounts;
end;
{ TObjectCounter }
class function TObjectCounter.InitInstance(Self: TClass;
Instance: Pointer): TObject;
var
count: Integer;
begin
if ObjectCounts.TryGetValue(Self, count) then
ObjectCounts[Self] := count + 1
else
ObjectCounts.Add(Self, 1);
Result := OldInitInstance(Self, Instance);
end;
class procedure TObjectCounter.CleanupInstance(Self: TObject);
var
count: Integer;
begin
if ObjectCounts.TryGetValue(Self.ClassType, count) then
if count = 1 then
ObjectCounts.Remove(Self.ClassType)
else
ObjectCounts[Self.ClassType] := count - 1;
OldCleanupInstance(Self);
end;
class procedure TObjectCounter.Init;
begin
ObjectCounts := TDictionary<TClass,Integer>.Create;
HookCode(@TObject.InitInstance, @InitInstance, @OldInitInstance);
HookCode(@TObject.CleanupInstance, @CleanupInstance, @OldCleanupInstance);
end;
class procedure TObjectCounter.Finalize;
begin
UnhookCode(@OldInitInstance);
UnhookCode(@OldCleanupInstance);
ObjectCounts.Free;
end;
initialization
TObjectCounter.Init;
finalization
TObjectCounter.Finalize;
end.