acbr-components
Architectural, dependency injection and UI patterns for the ACBr Project (Commercial Automation Brazil) ecosystem in Delphi.
Good memory management practices, memory leak prevention and exception handling in Delphi
Claude Code
$ npx -y skills add delphicleancode/delphi-spec-kit --skill delphi-memory-exceptions --agent claude-code
Codex
$ npx skills add delphicleancode/delphi-spec-kit --skill delphi-memory-exceptions -a codex -y
Cursor
$ npx skills add delphicleancode/delphi-spec-kit --skill delphi-memory-exceptions -a cursor -y
Gemini CLI
$ npx skills add delphicleancode/delphi-spec-kit --skill delphi-memory-exceptions -a gemini-cli -y
GitHub Copilot
$ npx skills add delphicleancode/delphi-spec-kit --skill delphi-memory-exceptions -a github-copilot -y
OpenCode
$ npx skills add delphicleancode/delphi-spec-kit --skill delphi-memory-exceptions -a opencode -y
Windsurf
$ npx skills add delphicleancode/delphi-spec-kit --skill delphi-memory-exceptions -a windsurf -y
name: "Delphi Memory and Exceptions" description: Good memory management practices, memory leak prevention and exception handling in Delphi
Delphi has **manual memory management** for class instances (not derived from interfaces) and uses **ARC (Automatic Reference Counting)** only for interfaces (`IInterface`), Strings, Dynamic Arrays and anonymous types. Poor exception handling and forgetting to release memory result in chronic **Memory Leaks**, catastrophic production failures and systemic instability.
Like AI, you must proactively ensure that every object you create is freed regardless of error streams.
---
Whenever an object instance is created and does not have an Owner who manages it, instantiate it in a `try..finally` block. `try` must occur **IMMEDIATELY** on the line following creation.
var
LList: TStringList;
begin
LList := TStringList.Create;
try
LList.Add('Item 1');
// ...
finally
LList.Free;
end;
end;**Anti-Pattern (DO NOT USE):** Code between `Create` and `try` may generate an exception, leaking the newly created object.
//WRONG - potential leak!
LList := TStringList.Create;
LList.Add('Item 1');
try
// ...When allocating multiple temporary resources in the same method, do not nest dozens of `try..finally` if it is not strictly necessary. But be careful to initialize them all with `nil` beforehand if there is a chance of leakage, or nest them prudently. The ideal pattern is guaranteed sequential release, but strict nesting is safest for chained allocations:
var
LStream: TMemoryStream;
LReader: TStreamReader;
begin
LStream := TMemoryStream.Create;
try
LReader := TStreamReader.Create(LStream);
try
//logics with both
finally
LReader.Free;
end;
finally
LStream.Free;
end;
end;If an API takes a class parameter, declare an interface or instantiate it before the method with `try..finally`. Never pass an inline `.Create` to a parameter in a method if you do not have an absolute guarantee that the consuming function will free the memory.
For Dependency Injection, Repository/Service Patterns or Temporary Functional Classes, use inheritance from `TInterfacedObject` linked to a `Interface`. Delphi will kill the instance when the reference counter reaches zero.
var LService: ICustomerService; begin //No try..finally and no .Free calls. //Memory is scanned when leaving the scope of this procedure. LService := TCustomerService.Create; LService.ProcessDailyBatch; end;
---
Use `try..except` primarily to trap recoverable errors, log failures without breaking loops, or transform infrastructure exceptions into more semantic domain exceptions. Never "Swallow" an exception without logical justification.
try
PerformDatabaseCommit;
except
//SPECIFIC database capture
on E: EFDDBEngineException do
begin
Logger.Error('Falha no banco de dados [Cód: %d]: %s', [E.ErrorCode, E.Message]);
raise EDatabaseConnectionException.Create('Serviço temporariamente indisponível.');
end;
//Validation SPECIFIC Capture
on E: EValidationException do
begin
ShowWarning(E.Message);
end;
end;**Anti-Pattern (DO NOT USE):** This blinds the application trace (hides `AccessViolations` and `Out of Memory`).
try ProcessData; except //Wrong! Hides any developer errors during debugging! end;
Do not use `raise Exception.Create(str)`. Declare cohesive exceptions to enable elegant interception by upper layers (REST Controllers, UI Interface).
type //Domain/Essence of the Rules EBusinessRuleException = class(Exception); ECustomerLimitReachedException = class(EBusinessRuleException); //Infrastructure EInfrastructureException = class(Exception); EDatabaseConnectionException = class(EInfrastructureException);
If you only need to perform a one-off log but want the exception to flow naturally to the global UI, just use pure `raise;`.
try
SomeDangerousCall;
except
on E: Exception do
begin
Logger.LogError('Critical failure', E);
raise; //REPROJECT the original exception with the same stack-trace
end;
end;---
When asked to write/refactor code: 1. Review whether each `TObject.Create` will result in a deallocation (`.Free` or Third-Party Ownership). 2. Inject `try..finally` if you notice legacy code without it. 3. If you generate Services, recommend Dependency Injection via Interfaces (`IService`) to simplify garbage scanning (GC). 4. In logic that may fail, create Typological Exceptions to validate flow and prevent error code spaghetti conditionals (`if return = -1 then`).
An opinionated ecosystem of rules, skills and steerings to elevate Delphi development to state-of-the-art with Artificial Intelligence.
Architectural, dependency injection and UI patterns for the ACBr Project (Commercial Automation Brazil) ecosystem in Delphi.
Pragmatic clean code standards for Delphi — concise, direct, no over-engineering
Delphi code review checklist — quality, security, performance, SOLID, memory
SOLID implementation patterns for Delphi projects — Repository, Service, Factory, Strategy with constructor injection and…
Implementation of the 23 GoF (Gang of Four) patterns in Object Pascal / Delphi with interfaces, TInterfacedObject and SOLID…
Standards for using DevExpress (DEXT) components in Delphi VCL applications
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…
Ask which skill or flow fits your situation. A router over the skills in this repo.