In a simple Delphi VCL application with one button on the form and the following OnButton event code:
procedure TForm1.Button1Click(Sender: TObject);
var
OpenDialog : TFileOpenDialog;
begin
OpenDialog := TFileOpenDialog.Create(nil);
try
OpenDialog.Options := OpenDialog.Options + [fdoPickFolders];
if not OpenDialog.Execute then
exit;
finally
OpenDialog.Free;
end;
end;
When I Execute the dialog my application memory usage more then doubles but after I OpenDialog.Free that memory is not released.(I'm using ProcessExplorer to see how much memory my application is using)
How can I make it so that after I Free the object my memory usage returns back to what it was before I called the dialog?
This is normal operation. Memory managers typically don't return memory to the system and instead cache it later re-use. Further, the modules that are loaded the first time a file dialog is shown remain loaded in your process.
It's entirely possible that the system caches other resources to improve performance for subsequent uses of file dialogs.
This behaviour leads to better performance. Were you to be able to force the memory to be returned to the system, your program would perform more slowly.
Your code is correct. There is no leak. There is no problem for you to solve.
Related
The problem I am facing is as follows.Please note I'm no pro at delphi pascal
To save a Large amount of memory and time I created a procedure:
procedure TForm1.Placeholder(tspath: STRING);
begin //rgbholder :TImage globally declared (Dinamicly create image)
rgbholder.Free;//Free previous image
rgbholder := timage.Create(self);
rgbholder.Width := 10;
rgbholder.Height := 10;
rgbholder.Visible := false;
rgbholder.Bitmap.LoadFromFile(TSpath);
end;
procedure TForm1.Image3Click(Sender: TObject);
begin
placeholder('Data\Grass\Grassanim1low.png');
bitmaplistanimation5.Stop;
bitmaplistanimation5.Loop := true;
//bitmaplistanimation5.AnimationBitmap.LoadFromFile('Data\Grass\Grassanim1low.png');
bitmaplistanimation5.AnimationBitmap.Assign( rgbholder.Bitmap);
bitmaplistanimation5.AnimationCount := 22;
bitmaplistanimation5.AnimationRowCount := 2;
bitmaplistanimation5.Duration := 2.5;
bitmaplistanimation5.PropertyName :='bitmap';
end;
Now my problem is freeing up that memory of the bitmaplistanimation5.AnimationBitmap.Assign(rgbholder.Bitmap);
When this code executes
bitmaplistanimation5.Stop;
bitmaplistanimation5.Enabled := false;
bitmaplistanimation5.AnimationBitmap.Free;
Everything goes well until I close the executable with a close; or by simply closing it with the exit in window.
After closing it throws a Application Error Exception EInvalidPointer in module Project1.exe at 00007A55. Invalid Pointer Operation
I don't think I'm trying to free memory that is already freed, I'm also not trying to free memory that was allocated somewhere other than the memory manager unless the placeholder procedure counts. Unless I'm missing something or not understanding something I should.
As a general rule, you should only call Free on an object that you created. You did not create this object, the TBitmapListAnimation control created it. So this code is a clear mistake on your part:
bitmaplistanimation5.AnimationBitmap.Free;
You will have to remove that.
I suspect that the right way to clear the memory from an FMX bitmap is to set the Width and Height properties of the bitmap to 0.
I wonder whether or not you really need to release this memory. If your program stops using the memory, and the system is short of memory, if can swap your unused memory to disk. It is common to find programmers who don't have a good understanding of virtual memory, taking actions like this that give no benefit. I would not be at all surprised if by trying to release this memory you actually made your program's performance worse rather than better.
Version used: Delphi 7.
I'm working on a program that does a simple for loop on a Virtual ListView. The data is stored in the following record:
type TList=record
Item:Integer;
SubItem1:String;
SubItem2:String;
end;
Item is the index. SubItem1 the status of the operations (success or not). SubItem2 the path to the file. The for loop loads each file, does a few operations and then, save it. The operations take place in a TStringList. Files are about 2mb each.
Now, if I do the operations on the main form, it works perfectly.
Multi-threaded, there is a huge memory problem. Somehow, the TStringList doesn't seem to be freed completely. After 3-4k files, I get an EOutofMemory exception. Sometimes, the software is stuck to 500-600mb, sometimes not. In any case, the TStringList always return an EOutofMemory exception and no file can be loaded anymore. On computers with more memory, it takes longer to get the exception.
The same thing happens with other components. For instance, if I use THTTPSend from Synapse, well, after a while, the software cannot create any new threads because the memory consumption is too high. It's around 500-600mb while it should be, max, 100mb. On the main form, everything works fine.
I guess the mistake is on my side. Maybe I don't understand threads enough. I tried to free everything on the Destroy event. I tried FreeAndNil procedure. I tried with only one thread at a time. I tried freeing the thread manually (no FreeOnTerminate...)
No luck.
So here is the thread code. It's only the basic idea; not the full code with all the operations. If I remove the LoadFile prodecure, everything works good. A thread is created for each file, according to a thread pool.
unit OperationsFiles;
interface
uses Classes, SysUtils, Windows;
type
TOperationFile = class(TThread)
private
Position : Integer;
TPath, StatusMessage: String;
FileStringList: TStringList;
procedure UpdateStatus;
procedure LoadFile;
protected
procedure Execute; override;
public
constructor Create(Path: String; LNumber: Integer);
end;
implementation
uses Form1;
procedure TOperationFile.LoadFile;
begin
try
FileStringList.LoadFromFile(TPath);
// Operations...
StatusMessage := 'Success';
except
on E : Exception do StatusMessage := E.ClassName;
end;
end;
constructor TOperationFile.Create(Path : String; LNumber: Integer);
begin
inherited Create(False);
TPath := Path;
Position := LNumber;
FreeOnTerminate := True;
end;
procedure TOperationFile.UpdateStatus;
begin
FileList[Position].SubItem1 := StatusMessage;
Form1.ListView4.UpdateItems(Position,Position);
end;
procedure TOperationFile.Execute;
begin
FileStringList:= TStringList.Create;
LoadFile;
Synchronize(UpdateStatus);
FileStringList.Free;
end;
end.
What could be the problem?
I thought at one point that, maybe, too many threads are created. If a user loads 1 million files, well, ultimately, 1 million threads is going to be created -- although, only 50 threads are created and running at the same time.
Thanks for your input.
There are (probably) no leaks in the code you show in the question.
I say probably because an exception raised during the Execute could result in a leak. The lifetime of the string list should be protected by a finally block.
FileStringList:= TStringList.Create;
try
LoadFile;
Synchronize(UpdateStatus);
finally
FileStringList.Free;
end;
That said, I expect the exception swallow in LoadFile means that you don't leak the string list.
You say that perhaps thousands of threads are created. Each thread reserves memory for its stack, and the default stack size is 1MB. Once you have thousands of 1MB stacks reserved, you can easily exhaust or fragment address space.
I've seen problems due to cavalier creation of threads in the past. For example I had a program that failed when it created and destroyed threads, with never more than 256 threads in existence. This was on a 16 core machine with 4GB address space. You probably have 2GB address space available.
Although you state that no more than 50 threads are in existence at any one moment, I'm not sure how you can be sure of that. Not least, because you have set FreeOnTerminate to True and thereby surrendered control over the lifetime of your threads.
My guess is that your problems are related to the number of threads you create. One thread per processor will suffice. Re-use your threads. It's expensive to create and destroy a thread for a small task.
If this is not enough to solve your problems then you will need to show the code that manages thread lifetime.
Finally, I wonder how much benefit you will extract from threading this app. If it is IO bound then the threaded version may well be slower!
Based on the information given, it's not possible to reproduce your error.
Some hints are made by Remy and David which might help you.
Looking at the structure of your program, the flow can be divided into two classical solutions.
The first part where you are delegating tasks to different threads, is a Single-Producer-Multiple-Consumer problem.
Here it can be solved by creating a small number of threads, passing them a thread-safe object queue.
The main thread then pushes the task objects into the queue. The consumer threads takes care of the individual file checking tasks.
The second part where the result is to be transfered to the main thread is a Multiple-Producer-Single-Consumer problem.
If you pass a second thread-safe object queue to the threads at initialization, they can easily put the results into the queue.
Drain the result queue from the main thread within a timer event.
This question might or might not solve my problem - but I hope to learn how Delphi/Windows can behave in a way which can cause this.
I have an application which uses a 3rd party component to load an Outlook .msg file.
In some cases (specific mails) the application freezes when calling SetLength (inside of the component, I have the source code).
This happens sometimes when setLength is called inside of a procedure which loads the properties from the file (stream). It happens the exact same place on the same mail - and can be reproduced every time.
Obviously the component does a lot of stuff and it is probably a sideeffect of some of this. However, the mails contains confidential data which I cannot send to the developer of the 3rd party component, so I cannot send it to him to debug it.
The program is running under windows XP on a domain.
The curious thing is that it only happens when the user running the program is not set to be administrator on the local machine.
ms := TMemoryStream.Create;
try
WriteStorageToStream(SubStorage, ms);
ApplyValue(ms, ms.Size)
finally
ms.Free;
end;
procedure ApplyValue(Stream: TStream; brLen: Integer);
var
s: AnsiString;
begin
SetLength(s, brLen); // this freezes it all. brLen=3512
FillChar(s[1], brLen, #0);
Stream.Read(s[1], brLen);
Value := s;
end;
What WriteStorageToStream does exactly is unknown to me, but since we are not manipulating the stream and brLen has an integer value, I assume it's irrelevant.
I'd say it was simple memory overwrite, causing a failure of the memory manager when the SetLength is called which then tries to use the memory management structures. The problem is in WriteStorageToStream(SubStorage, ms);
To find it, use the FastMM debug version with the memory overwrite detection options turned on.
There's absolutely no reason SetLength would freeze on a AnsiString that's only 3512 characters long. How are you sure that it's freezing there and not somewhere earlier (like in WriteStorageToSteam)? Presumably you're stepping through this in the debugger. Does the CPU spike to 100% on that process thread when it's frozen? The fact that it freezes only on certain emails indicates to me that something in the contents of those emails is causing the freeze. The call to SetLength has nothing to do with the contents; it only cares about the length.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
TStringList of objects taking up tons of memory in Delphi XE
I have a program that takes a while to run and uses a fair amount of memory (starts out at about 800 mb, ends at about 1.1 GB).
The problem I'm having is that even though the amount of memory it's using is fine, the amount of memory commited goes over 4GB and gives me an "Out of Memory" error.
Here is a screen shot of Resource Monitor:
The main thing that takes up the memory is a TStringList filled with an object that has a bunch of different values and a few stringlists
Does anyone know why it is committing so much more memory than I need, and how can I make my program not do that?
The commit size is the amount of memory allocated by the program (but is not necessarily in physical memory). As mentioned in the comments, it is quite possible that the program has a memory leak (e.g., it creates objects possibly but does not delete them). So even if the amount of memory in use is "reasonable", it doesn't necessarily represent the amount actually allocated, and that amount in a 32-bit system can't "typically" exceed 4GB. This question discusses leak detection tools that might be useful.
Your software probably contains a memory leak. Put this little piece of code right after your program's "main" block (.dpr file - press F7 to get there).
{$WARN SYMBOL_PLATFORM OFF}
ReportMemoryLeaksOnShutdown := DebugHook <> 0;
So, the end result should look similar to this:
begin
{$WARN SYMBOL_PLATFORM OFF}
ReportMemoryLeaksOnShutdown := DebugHook <> 0;
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
Then, run your program until you get some big memory usage and simply quit it. Delphi will show a nice window giving you the size of the memory leak as well as some tips about where they might be happening.
Good luck!
You didn't showed code, but this effect appears to be the result of a memory leak.
So, this TStringList (I'll call it parent) have objects associated, which have its own child TStringLists (which I suppose have only strings).
The easier way to do this memory management is letting the TStringList do it for you:
If in the Delphi version you have TStringList has the OwnsObjects property, set it to true. With this, every call to Delete and Clear methods will call the destructor of the objects associated with the parent list - and this will work even if cll parent.Free. If it doesn't implement, you'll have to do it yourself - overriding the Delete, Clear and Destroy methods of TStringList in a descendant class.
Make sure the destructor of the child objects clean correctly the objects created inside it - if one of the stringlists in a child objects has owned objects, you could use the same strategy in the above item.
An (oversimplified) example:
TMyChildObject = class
private
fMyListOfMagazineNames,
// This one will have TBitmap instances associated with the dogs names
fMyListOfDogNamesAndPhotos : TStringList;
fName: String;
public
//[properties, methods, whatever]
property Name: string read fName write fName;
constructor Create; virtual;
destructor Destroy; override;
end;
constructor TMyChildObject.Create;
begin
inherited Create;
fMyListOfMagazineNames = TStringList.Create;
fMyListOfDogNamesAndPhotos = TStringList.Create;
fMyListOfDogNamesAndPhotos.OwnsObjects := True;
end;
destructor TMyChildObject.Destroy;
begin
fMyListOfMagazineNames.Free;
fMyListOfDogNamesAndPhotos.Free;
inherited Destroy;
end;
An example of use:
var
MyObjList: TStringList;
begin
MyObjList := TStringList.Create;
MyObjList.OwnsObjects := True;
// Create your child objects
// And Free them at once
MyObjList.Free;
end;
As was stated in your previous question - thanks for having selected one answer.
The main solution to your problem is not to allocate all objects in memory. If your 28 MB initial data consume more than 1 GB of memory, you have a lot of redundant information.
You shall modify your algorithm as such:
Use a SQL database instead to process your data without memory issue (with proper indexes) - may be SQLite3 or embedded Firebird will work very well;
Leave the data on the input files, the memory-map them instead of allocating a copy in memory: use getter methods for each properties, to retrieve the value on the fly;
Use a NoSQL database (like this) which may be faster than a SQL database for inserting rows, and consume less disk space and memory;
Or... consider compressing the objects content (a fast compression is a good option).
I'm developing as small diabetes program using Delphi 5 and ADO. I do a little query like this:
function GetLowestGlucoseLevel(StartDate:string;EndDate:string): Integer;
var
Q:TADOQuery;
begin
try
Q:=TADOQuery.Create(Application); //Separate unit, owner set to App
Q.Connection:=dtMod.ADOCon;
Q.DisableControls;
Q.Close;
Q.SQL.Clear;
Q.SQL.Add('SELECT Min(qGlucose.Glucose) AS MinOfGlucose from qGlucose');
Q.Parameters[0].Value:=StartDate;
Q.Parameters[1].Value:=EndDate;
Q.Open;
Result:=Q.FieldByName('MinOfGlucose').AsInteger;
Q.Close;
finally
Q:=nil;
Q.Free;
end;
end;
The query runs OK and returns the result as expected. However, when I checked Windows Task Manager, memory usage keeps on rising rather than decreasing after the query.
How to fix this?
Thanks!
You are leaking the TADOQuery by first setting it to nil, and then calling Free on the nil variable (which does nothing)
Did you install Delphi 5 updates? The
RTM ADO implementation is known to
have issues.
Use FastMM4, it should work with
Delphi 5 as well, and tell you more
about where the leaks are.
The Delphi way:
function GetLowestGlucoseLevel(const StartDate:string; const EndDate:string): Integer;
var
Q:TADOQuery;
begin
Q:=TADOQuery.Create(nil); //(nil) because local use only. Placed before try\finally block
//because if it fails to .create then there would be no object to
//.Free
try
Q.Connection := dtMod.ADOCon;
//------can erase these------
//Q.DisableControls; //No controls attached so unnecessary
//Q.Close; //Q is local and was never opened so no need to close
//Q.SQL.Clear; //Q is local and was never filled so no need to clear
Q.SQL.Add('SELECT Min(qGlucose.Glucose) AS MinOfGlucose from qGlucose');
Q.Parameters[0].Value:=StartDate;
Q.Parameters[1].Value:=EndDate;
Q.Open;
Result := Q.FieldByName('MinOfGlucose').AsInteger;
Q.Close;
finally
Q.Free;
//Q := nil //not needed because Q's scope is local
end;
end;
Quote:
finally
Q:=nil;
Q.Free;
end;
You're kidding, right? First nil the variable, then free it? You're a genius! :-)
Use:
finally
Q.Free;
Q:=nil;
end;
Or don't even bother assigning nil to it, since Q is a local variable...
But rereading your code, I notice you use Application as owner. As a result, it will not really be a leak, since it will be freed when the application is freed. If you use a form, it would be freed when the owner form gets freed. What you should try is to call this query about 100.000 times to check if it keeps reserving memory or if it's just increasing memory until a certain size has been reached. The latter is more likely, since the memory is reserved for future ADO calls.
As others pointed out, the finally section should have the 2 statements reversed, like so:
finally
Q.Free;
Q:=nil; // <- not even necessary since this is a local var
end;
Or you can call SysUtils.FreeAndNil(Q) (if that is available in Delphi 5, not sure).
Beside that, the TaskManager is an awful instrument to determine memory usage anyway. You might release the memory for Q, but that does not automatically mean the Delphi memory manager releases the memory to the OS.
Aside inversing the lines as Arjan, jasonpenny and WorkShop Alex said, you can use Process Explorer to see the real consumption of memory (Private Bytes) of the process. Task Manager is not really suited to this task, as it only shows the working set of the process.