Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Memory leaks happens in nested anonymous method

In Delphi XE, the following code will cause memory leak:

procedure TForm1.Button1Click(Sender: TObject);
var P, B: TProc;
begin
  B := procedure
       begin
       end;

  P := procedure
       begin
         B;
       end;
end;

Run the code with

ReportMemoryLeaksOnShutdown := True;

and the memory manager prompt:

21-28 bytes: TForm1.Button1Click$ActRec x 1
like image 346
Chau Chee Yang Avatar asked Jun 08 '11 01:06

Chau Chee Yang


People also ask

What is the main cause of memory leaks?

A memory leak starts when a program requests a chunk of memory from the operating system for itself and its data. As a program operates, it sometimes needs more memory and makes an additional request.

Can a memory leak happen in managed languages?

Common Types of Memory Leaks. Leaks in managed platforms are effectively references to an element that is no longer necessary. There are many samples of this, but they all boil down to discarding said reference. The most common problem is caching.

How does memory leak happen in Python?

When a programmer forgets to clear a memory allocated in heap memory, the memory leak occurs. It's a type of resource leak or wastage. When there is a memory leak in the application, the memory of the machine gets filled and slows down the performance of the machine.

What happens when a memory leak occurs?

Memory leak occurs when programmers create a memory in heap and forget to delete it. The consequences of memory leak is that it reduces the performance of the computer by reducing the amount of available memory.


3 Answers

This is due to the way anonymous methods work. Anonymous methods are implemented as TInterfacedObject descendants, and if you have more than one in the same routine, they end up as two methods of the same object. It uses interfaces for reference counting so you don't end up leaking the objects. However, if an anonymous method references itself, that ends up throwing off the reference count and causing a memory leak. What you're seeing here is caused by a combination of these two things.

like image 132
Mason Wheeler Avatar answered Oct 02 '22 16:10

Mason Wheeler


This is a bug in the compiler (as far as I know). I opened QC83259 in Embarcadero's quality central about it.

You can work around this bug by creating the anonymous procedure in a routine. The following code won't leak.

procedure TForm1.Button1Click(Sender: TObject);
var P, B: TProc;
begin
  B := GetMethod(); //Note, the "()" are necessary in this situation.
  P := procedure
  begin
    B;
  end;
end;


function TForm1.GetMethod: TProc;
begin
  Result := procedure
  begin
  end;
end;
like image 30
Ken Bourassa Avatar answered Sep 29 '22 16:09

Ken Bourassa


I know I'm 2 years late to this discussion, but I've recently run into this memory leak within our code and I couldn't get Ken's suggested answer to work. So with the help of a colleague of mine we came up with a different answer to keep using the nested anonymous methods yet avoid any memory leaks.

Below is an example of the solution we found:

    procedure TForm1.Button1Click(Sender: TObject);
    var P, B: TProc;
    begin
        B := procedure
        begin
        end;

        P := procedure
        begin
          B;
        end;

        B := nil;
    end;

My belief is that due to the way local variables are bound for the purpose of extending their lives in order for the anonymous method to use it outside of the scope it was created in, that it is making a copy of the underlying interfaced object in order to move the variable from the stack to the heap, and in doing so it is calling AddRef which increments the reference counter. Setting the variable to nil after it has been used calls the Release which in turn decrements the reference counter back down to 0 which allows the interfaced object to be freed.

After doing this we have not seen the memory leaks that were occurring from before.

Whether this is a bug or not, I cannot answer that, but I am interested in hearing the opinions from others. We see this as a way to allow us to continue using anonymous methods in a nested form like this.

like image 23
Vysion Avatar answered Sep 28 '22 16:09

Vysion