Search code examples
memory-leakslinked-listdestructorfreepascal

Object Pascal Linked list destructor leaves one block unfreed


Implementing the destructor for this singly linked list class in Object Pascal, why is there always one memory block left unfreed at the end?

I have tried an iterative instead of recursive destructor but it gives the same result.

File LinkedListMWI.pas

    {$mode objfpc}{$H+}{$J-}
    
    unit LinkedListMWI;
    
    interface
    
    uses SysUtils; 
    
    type
      TNode = class
      private
        var
          FData: Integer;
          FNext: TNode;
      public
        constructor Create(Data: Integer);
        destructor Destroy(); override;
      end;
    
      TLinkedList = class
      private
        var
          FHead: TNode;
      
      public
        constructor Create(Items: Array of Integer);
        destructor Destroy(); override;
      end;
    
    implementation
    
    constructor TNode.Create(Data: Integer); 
    begin
      inherited Create();
      Self.FData := Data;
      Self.FNext := Nil;
    end;
    
    destructor TNode.Destroy();
    begin
      FreeAndNil(Self.FNext);
      inherited Destroy();
    end;
    
    constructor TLinkedList.Create(Items: Array of Integer);
    var
      Head, Last, ThisNode: TNode;
      ThisItem: Integer;
    begin
      inherited Create();
      Head := Nil;
      for ThisItem in Items do
      begin
        ThisNode := TNode.Create(ThisItem);
        if not Assigned(Head) then
        begin
          Head := ThisNode;
          Last := Head;
        end
        else
        begin
          Last.FNext := ThisNode;
          Last := ThisNode;
        end;
      end;
      Self.FHead := Head;
    end;
    
    { TODO Still one block unfreed }
    destructor TLinkedList.Destroy();
    begin
      FreeAndNil(Self.FHead);
      inherited Destroy;
    end;
    
    end.

File MWI.lpr

    {$mode objfpc}{$H+}{$J-}
    
    program mwi;
    
    uses SysUtils, LinkedListMWI;
    
    var 
      Nums: Array of Integer = (1, 2, 3, 4, 5, 6, 7);
      List: TLinkedList;
    begin
      List := TLinkedList.Create(Nums);
      FreeAndNil(List);
    end.

Compile with fpc -vwhine -glh MWI.lpr

Result:

15 memory blocks allocated : 1524/1536
14 memory blocks freed     : 1496/1504
1 unfreed memory blocks : 28
True heap size : 360448
True free heap : 360192
Should be : 360224
Call trace for block $0000FFFF80105500 size 28
  $0000000000400210  main,  line 11 of MWI.lpr
  $0000000000400168

Solution

  • The linked list code has no memory leak - the unfreed block is from somewhere else.

    I don't know how FPC handles global dynamic array variables that are initialized - if I had to guess I would say it is that.

    Try changing the code to this and check again:

    var
      List: TLinkedList;
    begin
      List := TLinkedList.Create([1, 2, 3, 4, 5, 6, 7]);
      FreeAndNil(List);`
    end.