ℹ️ Select 'Choose Exercise', or randomize 'Next Random Exercise' in selected language.

Choose Exercise:
Timer 00:00
WPM --
Score --
Acc --
Correct chars --

Delphi Memory Leak Detector with Object Tracking

Delphi / Object Pascal

Goal -- WPM

Ready
Exercise Algorithm Area
1type
2TTrackedObject = class
3FObject: TObject;
4FAllocationAddress: Pointer;
5FAllocationStack: TStack<string>; // Simplified stack representation
6FIsFreed: Boolean;
7end;
8
9TLeakDetector = class
10private
11FTrackedObjects: TDictionary<Pointer, TTrackedObject>;
12FLock: TCriticalSection;
13procedure RegisterObject(AObject: TObject; AAddress: Pointer; AStack: TStack<string>);
14procedure UnregisterObject(AAddress: Pointer);
15procedure ReportLeaks;
16public
17constructor Create;
18destructor Destroy;
19procedure TrackAllocation(AObject: TObject; AStack: TStack<string>);
20procedure TrackDeallocation(AObject: TObject);
21procedure FinalizeDetection;
22end;
23
24constructor TLeakDetector.Create;
25begin
26inherited Create;
27FTrackedObjects := TDictionary<Pointer, TTrackedObject>.Create;
28FLock := TCriticalSection.Create;
29end;
30
31destructor TLeakDetector.Destroy;
32begin
33// Ensure all tracked objects are freed before destroying the detector
34FinalizeDetection;
35FTrackedObjects.Free;
36FLock.Free;
37inherited Destroy;
38end;
39
40procedure TLeakDetector.TrackAllocation(AObject: TObject; AStack: TStack<string>);
41var
42ObjPtr: Pointer;
43begin
44if AObject = nil then
45Exit;
46
47ObjPtr := AObject;
48FLock.Enter;
49try
50RegisterObject(AObject, ObjPtr, AStack);
51finally
52FLock.Leave;
53end;
54end;
55
56procedure TLeakDetector.TrackDeallocation(AObject: TObject);
57var
58ObjPtr: Pointer;
59begin
60if AObject = nil then
61Exit;
62
63ObjPtr := AObject;
64FLock.Enter;
65try
66UnregisterObject(ObjPtr);
67finally
68FLock.Leave;
69end;
70end;
71
72procedure TLeakDetector.RegisterObject(AObject: TObject; AAddress: Pointer; AStack: TStack<string>);
73var
74Tracked: TTrackedObject;
75begin
76if FTrackedObjects.ContainsKey(AAddress) then
77begin
78// Object already tracked, potentially re-allocated. Mark as freed and re-register.
79Tracked := FTrackedObjects[AAddress];
80Tracked.FIsFreed := True; // Mark previous instance as freed
81// Optionally, log this re-allocation event.
82end;
83
84Tracked := TTrackedObject.Create;
85Tracked.FObject := AObject;
86Tracked.FAllocationAddress := AAddress;
87Tracked.FAllocationStack := AStack; // Store a copy or reference
88Tracked.FIsFreed := False;
89FTrackedObjects.Add(AAddress, Tracked);
90end;
91
92procedure TLeakDetector.UnregisterObject(AAddress: Pointer);
93var
94Tracked: TTrackedObject;
95begin
96if FTrackedObjects.TryGetValue(AAddress, Tracked) then
97begin
98Tracked.FIsFreed := True;
99end
100else
101begin
102// Attempting to free an object not tracked. This could indicate an issue.
103// Log this event for debugging.
104end;
105end;
106
107procedure TLeakDetector.FinalizeDetection;
108begin
109ReportLeaks;
110// Clean up tracked objects that were not freed
111for Tracked in FTrackedObjects.Values do
112begin
113if not Tracked.FIsFreed then
114begin
115// This is a leak. The object is still being tracked.
116// In a real scenario, you'd log details here.
117// For this example, we'll just ensure the TTrackedObject itself is freed.
118end;
119Tracked.Free;
120end;
121FTrackedObjects.Clear;
122end;
123
124procedure TLeakDetector.ReportLeaks;
125var
126LeakedCount: Integer;
127Tracked: TTrackedObject;
128begin
129LeakedCount := 0;
130// Iterate through all tracked objects to find those not freed
131for Tracked in FTrackedObjects.Values do
132begin
133if not Tracked.FIsFreed then
134begin
135Inc(LeakedCount);
136// Log details of the leaked object (e.g., type, allocation stack)
137// Example: OutputDebugString(PChar('Leak detected: ' + Tracked.FObject.ClassName + ' at address ' + IntToStr(NativeInt(Tracked.FAllocationAddress))));
138end;
139end;
140
141if LeakedCount > 0 then
142begin
143// Output a summary of leaks
144// Example: OutputDebugString(PChar(IntToStr(LeakedCount) + ' memory leaks detected.'));
145end
146else
147begin
148// Output a success message
149// Example: OutputDebugString('No memory leaks detected.');
150end;
151end;
152
153// Example usage (requires a mechanism to intercept allocations/deallocations)
154// This would typically involve overriding memory manager functions or using compiler directives.
155// For simplicity, assume TMyApplication.Create/Destroy calls TrackAllocation/TrackDeallocation.
Algorithm description viewbox

Delphi Memory Leak Detector with Object Tracking

Algorithm description:

This Delphi code defines a `TLeakDetector` class designed to identify memory leaks by tracking object allocations and deallocations. It maintains a dictionary of `TTrackedObject` instances, each holding a reference to a Delphi object, its allocation address, and a flag indicating if it has been freed. When an object is allocated, it's registered; when freed, it's marked. At the end of the application's lifecycle, `FinalizeDetection` iterates through the tracked objects, reporting any that were not marked as freed. This is a fundamental technique for debugging memory management issues in applications.

Algorithm explanation:

The `TLeakDetector` uses a `TDictionary` to map object memory addresses (pointers) to `TTrackedObject` records. Each `TTrackedObject` stores the actual object, its allocation address, a simplified call stack at allocation (for debugging), and a boolean `FIsFreed` flag. `TrackAllocation` registers an object by creating a `TTrackedObject` and adding it to the dictionary. `TrackDeallocation` finds the corresponding `TTrackedObject` by address and sets its `FIsFreed` flag to `True`. The `FinalizeDetection` method is crucial; it iterates through the dictionary. If a `TTrackedObject`'s `FIsFreed` flag is still `False`, it signifies a memory leak, and details are reported. The use of `TCriticalSection` ensures thread-safe access to the `FTrackedObjects` dictionary, which is essential in multi-threaded Delphi applications. The time complexity for tracking an allocation or deallocation is O(log N) on average for `TDictionary` operations, where N is the number of tracked objects. `FinalizeDetection` has a complexity of O(N) because it iterates through all tracked objects. Space complexity is O(N) to store the `TTrackedObject` instances.

Pseudocode:

CLASS TTrackedObject:
  ObjectReference
  AllocationAddress
  AllocationStack
  IsFreed (Boolean)
END CLASS

CLASS TLeakDetector:
  TrackedObjects (Dictionary<Address, TTrackedObject>)
  Lock (CriticalSection)

  METHOD Create():
    Initialize TrackedObjects and Lock
  END METHOD

  METHOD Destroy():
    Call FinalizeDetection
    Free TrackedObjects and Lock
  END METHOD

  METHOD TrackAllocation(Object, Stack):
    Acquire Lock
    IF ObjectAddress is already in TrackedObjects THEN
      Mark existing entry as Freed
    END IF
    Create new TTrackedObject
    Set ObjectReference, AllocationAddress, AllocationStack, IsFreed = False
    Add to TrackedObjects with ObjectAddress as key
    Release Lock
  END METHOD

  METHOD TrackDeallocation(Object):
    Acquire Lock
    IF ObjectAddress is in TrackedObjects THEN
      Set IsFreed = True for the corresponding TTrackedObject
    ELSE
      Log "Attempt to free untracked object"
    END IF
    Release Lock
  END METHOD

  METHOD FinalizeDetection():
    Call ReportLeaks
    FOR EACH TrackedObject in TrackedObjects DO
      IF TrackedObject.IsFreed is False THEN
        Log "Memory Leak Detected: " + TrackedObject.ObjectReference.ClassName
      END IF
      Free TrackedObject
    END FOR
    Clear TrackedObjects
  END METHOD

  METHOD ReportLeaks():
    Count leaks
    Log summary or detailed leak information
  END METHOD
END CLASS