[fpc-pascal] extreme memory growth using cthreads and default heap manager

Seth Grover sethdgrover at gmail.com
Thu Dec 10 22:26:08 CET 2015


I am experiencing a weird issue regarding threading and shared libraries
under Linux. I've boiled it down to a very simple test case in hopes you
can help me understand what I'm doing wrong.

I'm running this test with FPC 3.0 (built from source) on x86_64 Debian
Linux.

First, I have this shared library:

===========================================================================
library fpcso1;

{$mode objfpc}{$H+}

uses
  cthreads,
  // cmem,
  SysUtils;

procedure Blow; cdecl;
var
  p : pbyte;
begin
  p := GetMem(1024);
  FreeMem(p);
  p := nil;
end;

exports
  Blow name 'fpcso1_blow';

end.
===========================================================================

It is used by this program:
===========================================================================
program fpcprog;

{$mode objfpc}{$H+}

uses
  cthreads,
  cmem,
  Classes,
  SysUtils,
  DateUtils;

const
  lib1Name = 'libfpcso1.so';

procedure fpcso1_blow; cdecl; external lib1Name;

var
  finishedThreads : longint = 0;
  runningThreads : longint = 0;
  startedThreads : longint = 0;

type
  TTestThread = class(TThread)
  protected
    procedure Execute; override;
  public
    constructor Create;
  end;

  constructor TTestThread.Create;
  begin
    inherited Create(true, 1024*1024);
    FreeOnTerminate := true;
  end;

  procedure TTestThread.Execute;
  begin
    InterLockedIncrement(runningThreads);
    try
      fpcso1_blow();
    finally
      InterLockedIncrement(finishedThreads);
      InterLockedDecrement(runningThreads);
    end;
  end;

procedure BeginTestThread();
var
  tmpThread : TTestThread;
begin
  tmpThread := TTestThread.Create();
  tmpThread.Start;
end;

const
  threadCount = 100000;
  threadMaxConcurrent = 30;
var
  lastTime : TDateTime;
  lastCount : longint = 0;
begin
  lastCount := 0;
  lastTime := now;
  while (startedThreads < threadCount) do begin
    if (runningThreads < threadMaxConcurrent) then begin
      InterLockedIncrement(startedThreads);
      BeginTestThread();
    end else begin
      sleep(1);
    end;
    if MilliSecondsBetween(lastTime, now) >= 1000 then begin
      writeln(runningThreads, ' threads runningThreads, ',
                finishedThreads, ' threads finished (',
                finishedThreads-lastCount, '/sec)');
      lastCount := finishedThreads;
      lastTime := now;
    end;
  end;
  while (runningThreads > 0) do begin
    sleep(1000);
    writeln(runningThreads, ' threads runningThreads, ', finishedThreads,
              ' threads finished (', finishedThreads-lastCount, '/sec)');
    lastCount := finishedThreads;
  end;
  sleep(1000);
  writeln(runningThreads, ' threads runningThreads, ',
            finishedThreads, ' threads finished');

end.
===========================================================================

When I execute the program, over the course of the ten seconds it takes
to run, I watch the process' memory usage grow to over a gigabyte:

 1s  235.81 MiB
 2s  351.34 MiB
 3s  463.64 MiB
 4s  575.35 MiB
 5s  688.54 MiB
 6s  799.47 MiB
 7s  916.26 MiB
 8s    1.01 GiB
 9s    1.12 GiB
10s    1.15 GiB

However, if I uncomment the "// cmem," line in the library, the memory does
not grow.

Why does using the default memory manager seem to leak memory like crazy if
I'm doing heavy threading? I'm setting FreeOnTerminate to true in
conjunction
with creating the thread suspended, then calling Start, which the
examples in the wiki and documentation seems to indicate is valid.

Is cmem *required* if I'm using threading on Linux? I hope not, because
while this example is boiled down to as simple as I could make it, I'm
having the same issue in my production application, in which I'm using my
own power-of-two memory manager, and I would really like to figure out
what I can do to continue to use my own memory manager, plus threading,
without it leaking so much memory for every thread that starts/finishes.

Thanks,

-Seth Grover
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freepascal.org/pipermail/fpc-pascal/attachments/20151210/b136e4f1/attachment.html>


More information about the fpc-pascal mailing list