Comments (11)
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.
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.
If this is called from a thread, maybe that thread doesn't process messages.
from omnithreadlibrary.
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.
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.
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.
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.
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.
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.
Currently, there's no other way than processing messages.
from omnithreadlibrary.
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)
- Error 1400 HOT 1
- Alexandria HOT 1
- Designtime Release Config incorrect LIB suffix HOT 1
- ForEach not working for objects?
- Madexcept and OTL HOT 2
- Compilation of Release 3.07.9 fails with D2010 HOT 1
- Parallel.For() does not support Int64 (but Delphi's TParallel.For() does)
- Installation on Delphi 11 (GetIt and GroupProj) HOT 2
- PostMessage related Quota error during peak machine latencies
- Bad address when casting FWaitHandle object to TWaiter
- Parallel.ForEach<> inside Parallel.Future<> seems to leak threads HOT 1
- Dont Install on Alexandria
- Add Delphi 12 support
- Release 3.07.10 does not compile on Delphi older than 10.3 Rio HOT 1
- 3.07.10 please fix hints
- Invalid Delphinus.install.json file
- Out of memory
- Enhancement : Enqueue a message with priority in the TOmniMessageQueue
- Memory Leak When Terminate(0) a Runing Thread
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from omnithreadlibrary.