# Importance of Proper Memory Management

Why is proper memory management so important for a web application?

The answer is simple: like any other server application, uniGUI servers are designed to run continuously. Any harmful memory operation can adversely affect server functionality and stability. These effects may remain hidden and undetected when server load is low, but will become visible as more clients request services.

Now let's discuss those harmful memory operations in more detail.

## Memory Leak

A memory leak happens when a manually allocated memory is never released. Sources of memory leaks can be various. A very common mistake is to create an object dynamically without adding proper code to dispose it. The following code shows an example of a memory leak:

{% code title="Example (memory leak)" %}

```pascal
A := TSomeControl.Create(nil);

A.Property1 := 0;

A.Run;

A.Free;
```

{% endcode %}

At first glance the above code may look correct, as it calls the `Free()` method to dispose the created control. However, what will happen if the `Run()` method fails and raises an exception? In that case the call to `Free()` will be skipped and a memory leak will occur. This is the corrected version of the same code:

{% code title="Corrected (try..finally)" %}

```pascal
A := TSomeControl.Create(nil);

try
    A.Property1 := 0;
    A.Run;
finally
    A.Free;
end;
```

{% endcode %}

In the previous snippet the `Free()` method will always be called regardless of the code in the `try .. finally` block.

The following code shows a wrong solution (it won't produce a memory leak, but it will cause memory corruption):

{% code title="Incorrect (may cause corruption)" %}

```pascal
try
    // consider that an exception occurs while creating the object
    A := TSomeControl.Create(nil);
    A.Property1 := 0;
    A.Run;
finally
    // in this case variable A will not be initialized and a call
    // to Free may lead to memory corruption
    A.Free;
end;
```

{% endcode %}

If the first statement fails to create the object `A` by throwing an exception, the subsequent request to free `A` will attempt to release an uninitialized variable. The failure to create the object does not assign `nil` to the variable. Attempting to release an object pointing to a random location can create memory corruption or trigger an Access Violation.

## Memory Corruption

A memory corruption occurs when a memory operation overwrites another memory location already occupied by an object or variable. Memory corruptions are more harmful than memory leaks. They can remain hidden for some time, but eventually you will start observing Access Violation errors in your application and uniGUI log files.

There are many sources of memory corruption, most of them resulting from bad coding habits. Some habits may not be harmful in a desktop VCL application, but in a server application their adverse effects will become apparent.

Perhaps one primary source of memory corruption in a multithreaded server application is using global variables. If a server application needs global variables, it is necessary to protect access to them. In a standard VCL application using global variables is common, but in a multithreaded application they should be used only when strictly necessary.

While using ordinal variables such as integers will not lead to an immediate memory corruption, using dynamic global strings can cause memory corruption. Memory corruption is only one side effect of using global variables — another important issue is that globals are shared between sessions.

Consider this scenario:

You have an application with a login form and you save the user information in a record variable.

{% code title="User record type" %}

```pascal
type
TUserRecord = record
    Name, Surname: string;
end;
```

{% endcode %}

Now declare it as a global variable in a unit (the wrong way):

{% code title="Wrong: global variable" %}

```pascal
var
  CurrentUser: TUserRecord;
```

{% endcode %}

After a new user logs in, assign the user name to this variable:

{% code title="Assigning to global" %}

```pascal
procedure TMainForm.UniBitBtn1Click(Sender: TObject);
begin
  CurrentUser.Name := UniNameEdit.Text;
  CurrentUser.Surname := UniSurnameEdit.Text;
end;
```

{% endcode %}

There are two major issues with that scenario:

* When a new session is created and user #1 logs in, their name is assigned to the `CurrentUser` variable. If another session is created and user #2 logs in, `CurrentUser` is overwritten with the new user information for the current session. The first session loses the previously saved user information.
* This scenario can easily lead to severe memory corruptions. With even moderate traffic, concurrent writes from multiple threads can cause string corruption. In Delphi, strings are dynamic memory locations managed by the memory manager. When two concurrent threads write to the same string, pointer corruption can occur.

### Correct approach in uniGUI

In uniGUI, each session comes with its set of modules and objects which are public to that session but private to others. Forms and modules are examples of such objects. Each session has its own private copy of MainForm, other forms, MainModule and DataModules (DataModules created with the uniGUI wizard).

If you want a "global" variable for a session, declare it as a field or property of one of those session-specific objects. By doing so, the variable is global or public for its parent session but private to other sessions, avoiding the memory issues described above.

Re-implement the scenario using `MainModule` as the container class for `UserRecord`. Add a new property named `UserRecord` to the `TUniMainModule` class:

{% code title="Session-scoped UserRecord in MainModule" %}

```pascal
type
  PUserRecord = ^TUserRecord;

  TUserRecord = record
    Name, Surname: string;
  end;

  TUniMainModule = class(TUniGUIMainModule)
  private
    { Private declarations }
    FUserRecord: TUserRecord;
    function GetUserRecord: PUserRecord;
  public
    { Public declarations }
    property UserRecord: PUserRecord read GetUserRecord;
  end;
```

{% endcode %}

Helper functions and implementation:

{% code title="UniMainModule helper and getter" %}

```pascal
function UniMainModule: TUniMainModule;

implementation

{$R *.dfm}

uses
  UniGUIVars, ServerModule, uniGUIApplication;

function UniMainModule: TUniMainModule;
begin
  Result := TUniMainModule(UniApplication.UniMainModule)
end;

function TUniMainModule.GetUserRecord: PUserRecord;
begin
  Result := @FUserRecord;
end;
```

{% endcode %}

This ensures each session accesses its own private copy of `UserRecord`, avoiding memory issues from global variables.

Finally, access `UserRecord` from other forms and modules like this:

{% code title="Assigning to session-scoped UserRecord" %}

```pascal
procedure TMainForm.UniBitBtn1Click(Sender: TObject);
begin
  UniMainModule.UserRecord.Name := UniNameEdit.Text;
  UniMainModule.UserRecord.Surname := UniSurnameEdit.Text;
end;
```

{% endcode %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://unigui-doc.falconsistemas.com.br/unigui-manual-en-us/developers-guide/application-design-considerations/web-application-stability/memory-management/importance-of-proper-memory-management.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
