Skip to content
Development
Skill

/delphi-memory-exceptions

Good memory management practices, memory leak prevention and exception handling in Delphi

From plugin
delphi-spec-kit
5818 skills1 command

Claude Code

$ npx -y skills add delphicleancode/delphi-spec-kit --skill delphi-memory-exceptions --agent claude-code

SKILL.md

delphi-memory-exceptions.SKILL.md
name: "Delphi Memory and Exceptions"
description: Good memory management practices, memory leak prevention and exception handling in Delphi

🧠 Memory and Exceptions Management in Delphi

Contexto

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.

Objectives of this Skill

  • Teach how to generate safe blocks of `try..finally`.
  • Prevent Memory Leaks by advising on `Free` and `FreeAndNil`.
  • Promote the use of Interfaces for memory automation.
  • Institute defensive and typed handling of Exceptions (`try..except`).
  • Introduce custom Domain Exceptions.

---

🛑 Memory Management: Critical Rules

1. The Gold Standard: `try..finally`

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
    // ...

2. Multiple Objects in the Same Block

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;

3. Avoid Creating Objects for Single Passage

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.

4. Garbage Collection via Intefaces

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;

---

🚨 Exception Handling: The Transparent Standard

1. Specific, Not Generic Catches

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;

2. Creating Exceptions Based on Business Logic (DDD)

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);

3. Encapsulating Errors and `Raise` without Modifying Context

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;

---

💡 AI Action Flow

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`).

Read more
@delphicleancode
Ships withdelphi-spec-kit

An opinionated ecosystem of rules, skills and steerings to elevate Delphi development to state-of-the-art with Artificial Intelligence.

Stars on GitHub

Momentum

stars in total
58
Star history of delphicleancode/delphi-spec-kit on GitHub, a chart by star-history.com

Other skills on delphi-spec-kit.

More skills from other plugins.

brainstorming
Auto-invoked

brainstorming

You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…

@obra@obraInstall Skill
ask-matt

ask-matt

Ask which skill or flow fits your situation. A router over the skills in this repo.

skills2w309k
@mattpocock@mattpocockInstall Skill
accessibility
Auto-invoked

accessibility

Design, implement, and audit accessible UI to WCAG 2.2 Level AA across Web, iOS, and Android — semantic ARIA roles and labels,…

ecc2w293k
@affaan-m@affaan-mInstall Skill
compiler-commit

compiler-commit

Use when you want to verify compiler changes and commit with the correct convention. Runs tests, lint, and format, then commits…

react5d252k
@facebook@facebookInstall Skill

Questions about delphi-memory-exceptions.

Which coding agents can use delphi-memory-exceptions?
delphi-memory-exceptions installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.