Code Monkey home page Code Monkey logo

Comments (11)

gabr42 avatar gabr42 commented on August 28, 2024

a) Create a MRE to report a problem: https://stackoverflow.com/help/minimal-reproducible-example.
b) I'll go on a limb and guess that you're doing this from a console program. If that's the case, see: http://www.omnithreadlibrary.com/book/chap05.html#introotl-messagelooprequired-console

from omnithreadlibrary.

hundreAd100 avatar hundreAd100 commented on August 28, 2024

no, not a console application
sadly, this is NOT easily reducible to MRE
this will require work but i'll see what i can do

from omnithreadlibrary.

gabr42 avatar gabr42 commented on August 28, 2024

If this is called from a thread, maybe that thread doesn't process messages.

from omnithreadlibrary.

hundreAd100 avatar hundreAd100 commented on August 28, 2024

problem is reproducible even in single-thread, HOWEVER memory does get freed after procedure finishes, in multi-thread the memory remains allocated EVEN AFTER the thread is done running and freed

will post mre momentarily

from omnithreadlibrary.

hundreAd100 avatar hundreAd100 commented on August 28, 2024

having set ReportMemoryLeaksOnShutdown := True;, on app exit i am sometimes getting:

An unexpected memory leak has occurred. The unexpected small block leaks are:

1 - 8 bytes: Unknown x 2
25 - 40 bytes: TBits x 2
73 - 88 bytes: TOmniIntegerSet x 2, TOTPWorkItem x 2
105 - 120 bytes: TOmniTask x 2

from omnithreadlibrary.

hundreAd100 avatar hundreAd100 commented on August 28, 2024

MRE

unit in use:

unit Unit_TBuilding;

interface

uses
  System.Math;

type
  TBuilding = record
    Index, Level, Panorama: Integer;
    Townhall: Boolean;
    X, Y: Double;
  end;

  TBuildingDynArray = array of TBuilding;

  TSolution = record
    Level, Panorama: Integer;
  end;

  TSolutionDynArray = array of TSolution;

const
  LEVEL_MAX = 5;
  LEVEL_MIN = 1;
  PANORAMA_MAX = 5;
  PANORAMA_MIN = 0;
  POPULATION_VIA_LEVEL: array [LEVEL_MIN .. LEVEL_MAX] of Integer = (197, 239,
      283, 331, 381);
  POPULATION_VIA_PANORAMA: array [PANORAMA_MIN .. PANORAMA_MAX] of Integer = (0,
      80, 139, 193, 253, 319);
  RADIUS_PANORAMA: array [LEVEL_MIN .. LEVEL_MAX] of Double = (4, 4.25,
      5, 6, 6.75);
  RADIUS_TOWNHALL = 20;

function Distance(const Building1, Building2: TBuilding): Double;
procedure Panorama(var Solutions: TSolutionDynArray);
procedure PertinentPanoramas(const Residences: TBuildingDynArray);

implementation

var
  FPertinentPanoramas: array of array [LEVEL_MIN .. LEVEL_MAX]
      of array of Integer;

function Distance(const Building1, Building2: TBuilding): Double;
begin
  Result := Sqrt(Power(Building1.X - Building2.X, 2) +
      Power(Building1.Y - Building2.Y, 2));
end;

procedure PertinentPanoramas(const Residences: TBuildingDynArray);
var
  I, Level, J: Integer;
begin
  SetLength(FPertinentPanoramas, Length(Residences));
  for I := Low(FPertinentPanoramas) to High(FPertinentPanoramas) do
    for Level := Low(FPertinentPanoramas[I]) to High(FPertinentPanoramas[I]) do
    begin
      SetLength(FPertinentPanoramas[I, Level], 0);
      for J := Low(Residences) to High(Residences) do
        if (I <> J) and (Distance(Residences[I], Residences[J]) <=
            RADIUS_PANORAMA[Level]) then begin
          SetLength(FPertinentPanoramas[I, Level],
              Length(FPertinentPanoramas[I, Level]) + 1);
          FPertinentPanoramas[I, Level,
              High(FPertinentPanoramas[I, Level])] := J;
        end;
    end;
end;

procedure Panorama(var Solutions: TSolutionDynArray);
var
  I, J: Integer;
begin
  for I := Low(Solutions) to High(Solutions) do
    with Solutions[I] do begin
      Panorama := Level;
      for J := Low(FPertinentPanoramas[I, Level])
          to High(FPertinentPanoramas[I, Level]) do
        if Level > Solutions[FPertinentPanoramas[I, Level, J]].Level then
          Panorama := Panorama + 1
        else
          Panorama := Panorama - 1;
    end;
end;

end.

main form:

unit Unit1;

interface

uses
  Winapi.Windows,
  System.Math,
  System.SysUtils,
  Vcl.Forms,
  Winapi.Messages,
  Vcl.StdCtrls,
  Vcl.Controls,
  System.Classes,
  System.Threading;

type
  TForm1 = class(TForm)
    ListBox1: TListBox;
    Button2: TButton;
    Button4: TButton;
    Button5: TButton;
    procedure Button4Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button5Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

uses
  Unit_TBuilding,
  OtlParallel;

// --- MRE --- SINGLE THREAD ---------------------------------------------------
const
  GENERATIONS = 250;
  GUI_UPDATE_INTERVAL = 250;
  MININT = -2147483648;
  SOLUTIONS_POOL = 10000;
  UPPERBOUND_ABSENT_TOWNHALL = 4;

type
  TSolutionPoolDynArray = array of TSolutionDynArray;

var
  FSolutionsPool: TSolutionPoolDynArray;

function Evaluate(const Residences: TBuildingDynArray;
    const SolutionsPool: TSolutionPoolDynArray): Integer;
var
  I: Integer;
begin
  Result := -1;
  Parallel.ForEach(Low(SolutionsPool), High(SolutionsPool)).Execute(
    procedure(const I: Integer)
//     TParallel.For(Low(SolutionsPool), High(SolutionsPool),
//     procedure(I: Integer)
    begin
      Panorama(SolutionsPool[I]);
    end);
end;

procedure Optimize(const Residences: TBuildingDynArray);
var
  I: Integer;
begin
  RandSeed := 123; // MRE REPRODUCIBLE RANDOM
  for I := 0 to GENERATIONS do begin
    Evaluate(Residences, FSolutionsPool);
    if I mod 25 = 0 then // MRE
      with Form1.ListBox1 do begin
        Items.Add(String.Format('Generation %d', [I]));
        Update;
      end;
  end;
end;

procedure xExecute;
var
  I, J: Integer;
  Residences: TBuildingDynArray;
begin
  // MRE CREATE DUMMY INPUT
  SetLength(Residences, 290);
  for I := Low(Residences) to High(Residences) do
    with Residences[I] do begin
      Index := I;
      Level := RandomRange(1, 5 + 1);
      X := RandomRange(1, 100);
      Y := RandomRange(1, 100);
    end;
  SetLength(FSolutionsPool, SOLUTIONS_POOL, Length(Residences));
  for I := Low(FSolutionsPool) to High(FSolutionsPool) do
    for J := Low(FSolutionsPool[I]) to High(FSolutionsPool[I]) do
      FSolutionsPool[I, J].Level := RandomRange(1, 5 + 1);
  // PertinentPanoramas = COMPUTED ONCE THEN REMAINS CONSTANT (SO IRRELEVANT?)
  PertinentPanoramas(Residences);
  Optimize(Residences);
  Form1.ListBox1.Items.Add('Done');
end;

procedure TForm1.Button4Click(Sender: TObject);
begin
  xExecute;
  // MRE: MEMORY ***FREED***
end;

// --- MRE --- MULTI THREADS ---------------------------------------------------
type
  Tmre = class(TThread)
  strict protected
    procedure Execute; override;
  end;

procedure Tmre.Execute;
begin
  inherited;
  xExecute;
  // MRE: MEMORY *** NOT FREED***
end;

var
  blah: Tmre;

procedure TForm1.Button2Click(Sender: TObject);
begin
  blah := Tmre.Create;
  // MRE listbox access should be Synchnized, i know; NOT THE PROBLEM
end;

procedure TForm1.Button5Click(Sender: TObject);
begin
  blah.Free;
  // MRE: MEMORY *** STILL NOT FREED***
end;

end.

from omnithreadlibrary.

hundreAd100 avatar hundreAd100 commented on August 28, 2024

another even simpler MRE:

procedure mre;
var
  I: Integer;
  blah: array of integer;
begin
  SetLength(blah, 290);
  Parallel.ForEach(Low(blah), High(blah)).Execute(
    procedure(const I: Integer)
    begin
      blah[I] := 0;
    end);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  I: Integer;
begin
  for I := 1 to 100 do begin
    sleep(100); // MRE: SO POSSIBLE TO SEE MEMORY USAGE IN TASK MANAGER
    mre;
  end;
  beep(40,40); // MRE: SIGNAL DONE
end;

from omnithreadlibrary.

gabr42 avatar gabr42 commented on August 28, 2024

Well, yes - that's the same issue as I'm talking about. While you're in the external for loop, messages are not processed and OTL doesn't do the cleanup. That's just as it is.

from omnithreadlibrary.

hundreAd100 avatar hundreAd100 commented on August 28, 2024

so do application.processmessages? this will kill performance
is there a way to force parallel.for to cleanup when it ends processing the .foreach?

from omnithreadlibrary.

gabr42 avatar gabr42 commented on August 28, 2024

Currently, there's no other way than processing messages.

from omnithreadlibrary.

hundreAd100 avatar hundreAd100 commented on August 28, 2024

your implementation is faster than delphi's tparallel.for by ~+10% but i'll need to test and see how much performance is hurt by application.processmessages
regardless, the memory usage during foreach may well be too extreme (even if freed afterwards)
i'm not sure this is usable for my needs, but thank you for your time & effort regarding this issue

from omnithreadlibrary.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.