I'm using DUnit and FastMM to catch unfinalized memory blocks but there seems to be a Bug. I dunno if its in FastMM, DUnit or in Delphi itself, but here goes:
When my Test Case has internal strings, the test fails with memory leaks. If I run the same test again without closing the DUnit GUI, the test passes OK. The same occours with DUnit GUI Testing, I believe for the same reason. There are no Leaks in my app, the proof is that FastMM doesn't generate the leak report in those cases.
Question 1: Is there a way to ignore them without setting the AllowedMemoryLeakSize
Question 2: I'm using Delphi 7, any news if this fix in Delphi XE?
My actual test configuration:
test.FailsOnNoChecksExecuted := True;
test.FailsOnMemoryLeak := True;
test.FailsOnMemoryRecovery := False;
test.IgnoreSetUpTearDownLeaks := True;
Here's a sample code (implementation only)
procedure TTest.Setup;
begin
A := 'test';
end;
procedure TTest.TearDown;
begin
// nothing here :)
end;
procedure TTest.Test;
begin
CheckTrue(True);
end;
Thanks!!!!
UPDATE: The problem i'm facing is documented in http://members.optusnet.com.au/mcnabp/Projects/HIDUnit/HIDUnit.html#memoryleakdetection
But the same link doesn't present a solution other than running the same test again.
Actually, strictly speaking your test is leaking memory on the first run.
It's not a bug in FastMM, DUnit or in Delphi, the bug is in your test.
Let's start by clearing up misconceptions, and explaining some inner workings:
Misconception: FastMM proves there are no leaks in my app
The problem here is that FastMM can give you a false sense of security if it doesn't detect leaks. The reason is that any kind of leak detection has to look for leaks from checkpoints. Provided all allocations done after the Start checkpoint are recovered by the End checkpoint - everything's cool.
So if you create a global object Bin, and send all objects to the Bin without destroying them, you do have a memory leak. Keep running like and your application will run out of memory. However, if the Bin destroys all its objects before the FastMM End checkpoint, FastMM won't notice anything untoward.
What's happening in your test is FastMM has a wider range on its checkpoints than DUnit leak detection. Your test leaks memory, but that memory is later recovered by the time FastMM does its checks.
Each DUnit test gets its own instance for multiple runs
DUnit creates a separate instance of your test class for each test case. However, these instances are reused for each run of the test. The simplified sequence of events is as follows:
Start checkpoint
Call SetUp
Call the test method
Call TearDown
End checkpoint
So if you have a leak between those 3 methods - even if the leak is only to the instance, and will be recovered as soon as the object is destroyed - the leak will be reported. In your case, the leak is recovered when the object is destroyed. So if DUnit had instead created & destroyed the test class for each run, no leak would be reported.
NOTE This is by design, so you can't really call it a bug.
Basically DUnit is being very strict about the principle that your test must be 100% self contained. From SetUp to TearDown, any memory you allocate (directly/indirectly) must be recovered.
Constant strings are copied whenever they are assigned to a variable
Whenever you code StringVar := 'SomeLiteralString' or StringVar := SomeConstString or StringVar := SomeResourceString the value of the constant is copied (yes, copied - not reference counted)
Again, this is by design. The intention is that if the string was retrieved from a library, you don't that string to be trashed if the library is unloaded. So it's not really a bug, just an "inconvenient" design.
So the reason your test code leaks memory on the first run is that A := 'test' is allocating memory for a copy of "test". On the subsequent runs, another copy of "test" is made, and the previous copy is destroyed - but the net memory allocation is the same.
Solution
The solution in this particular case is trivial.
procedure TTest.TearDown;
begin
A := ''; //Remove the last reference to the copy of "test" and presto leak is gone :)
end;
And in general, you shouldn't have to do much more than that. If your test creates child objects that reference copies of constant strings, those copies will be destroyed when the child objects are destroyed.
However, if any of your tests pass references to strings to any global objects / singletons (naughty, naughty, you know you shouldn't be doing that), then you'll have leaked a reference and hence some memory - even if it is recovered later.
Some further observations
Going back to the discussion about how DUnit runs tests. It is possible for separate runs of the same test to interfere with each other. E.g.
procedure TTestLeaks.SetUp;
begin
FSwitch := not FSwitch;
if FSwitch then Fail('This test fails every second run.');
end;
Expanding on the idea, you can get your test to "leak" memory on the first and every second(even) run.
procedure TTestLeaks.SetUp;
begin
FSwitch := not FSwitch;
case FSwitch of
True : FString := 'Short';
False : FString := 'This is a long string';
end;
end;
procedure TTestLeaks.TearDown;
begin
// nothing here :( <-- note the **correct** form for the smiley
end;
This doesn't really result in overall consumption of memory increasing because each alternate run recovers the same amount of memory that is leaked on every second run.
The string copying results in some interesting (and perhaps unexpected) behaviour.
var
S1, S2: string;
begin
S1 := 'Some very very long string literal';
S2 := S1; { A pointer copy and increased ref count }
if (S1 = S2) then { Very quick comparison because both vars point to the same address, therefore they're obviously equal. }
end;
However....
const
CLongStr = 'Some very very long string literal';
var
S1, S2: string;
begin
S1 := CLongStr;
S2 := CLongStr; { A second **copy** of the same constant is allocated }
if (S1 = S2) then { A full comparison has to be done because there is no shortcut to guarantee they're the same. }
end;
This does suggest an interesting, though extreme and probably ill-advised workaround just due to the sheer absurdness of the approach:
const
CLongStr = 'Some very very long string literal';
var
GlobalLongStr: string;
initialization
GlobalLongStr := CLongStr; { Creates a copy that is safely on the heap so it will be allowed to be reference counted }
//Elsewhere in a test
procedure TTest.SetUp;
begin
FString1 := GlobalLongStr; { A pointer copy and increased ref count }
FString2 := GlobalLongStr; { A pointer copy and increased ref count }
if (FString1 = FString2) then { Very efficient compare }
end;
procedure TTest.TearDown;
begin
{... and no memory leak even though we aren't clearing the strings. }
end;
Finally / Conclusion
Yes, apparently this lengthy post is going to end.
Thank you very much for asking the question.
It gave me a clue as to a related problem I remember experiencing a while back. After I've had a chance to confirm my theory, I'll post a Q & A; as others might also find it useful.
I would try the current release from Subversion first (but this version does not work with Delphi 7, only 2007 and newer):
In the commit log, one version has a comment about a fix in the area
Revision 40 Modified Fri Apr 15 23:21:27 2011 UTC (14 months ago)
move JclStartExcetionTracking and JclStopExceptionTracking out of
DUnit recursion to prevent invalid memory leak reporting
I found a way to lessen the problem: instead of working with Strings, I used ShortStrings and WideStrings in the Test Classes. No leaks poped from them.
It's not the solution, which by the way seems to be solved in the newest Delphi versions.
Bottom line is that the detected leak may be irrelevant to the test case being executed but it is a legitimate leak at the time it is detected. The memory for the string was unallocated prior to entry into the SetUp procedure and it is not deallocated prior to exiting from the TearDown procedure. So it is a memory leak until either the string variable is reassigned or the test case is destroyed.
For strings and dynamic arrays you can use SetLength(<VarName>, 0) in the TearDown procedure.
Related
I am having a memory problem that cannot explain root cause, please help me!
The problem is as follows:
My program throws exception when i exit.
I investigated and thought that the cause of the error was the use Copymemory function to copy the record containing the variable have string data type.
Below is my demo program by delphi 2009:
In *.dpr file, I added ShareMem unit for use BorlndMM.dll instead of using FastMM memory management.
I define a struct containing a String variable.
Allocate 1 array of 2048 PByte elements.
Use Memory Copy function to copy 2 struct.
finally, Free array 2048.
when i exit program, my program threw exception.
type
TMyStructure = record
F1: TMyStructure;
str1: string;
unit 1
procedure TForm9.FormCreate(Sender: TObject);
var
i: Integer;
begin
F1.str1 := 'This is a string to demo for copying the String data type
using the Copymemory method';
end;
unit 2
procedure TForm8.btn1Click(Sender: TObject);
var
Form9: TForm9;
i: Integer;
s1: array[0..2048-1] of PByte;
begin
// Alloc 1st 2048 segments, each segment gain 1KB
for i := 0 to Length(s1) - 1 do
begin
s1[i] := AllocMem(1024);
end;
// Create Form9
Form9 := TForm9.Create(Owner);
// -> ERROR
CopyMemory(#Self.F1, #Form9.F1, SizeOf(TMyStructure));
// -> OK
// Self.F1 := Form9.F1;
// Free memory s1 array
for i := 0 to Length(s1) - 1 do
begin
FreeMem(s1[i]);
end;
end;
Note:
I have known management in memory of string is reference counting.
I've been investigating because of the use of Memorycopy, so reference count of the string is not incremented although there are 2 references to it.
I investigated that when the string was free for the first time, its reference count dropped to zero, but that memory was not returned to the OS.However, it seems that when another free variable has a nearby address, that memory loses the reference, so when accessing the second free will cause an exception.
Since no source code can be found as well as documentation describing the operation mechanism of BorlndMM.dll should read the spec as well as GetMem.inc source code file to understand the mechanism of operation FastMM and speculate the root cause of the bug. I'm guessing when a free variable, BorlndMM find ahead and after that free space and the combination leads to the memory area that can not be referenced anymore.Of course, using Memorycopy to copy two string variables is a action wrong and must fix. However, I would like to understand how the Memory Management mechanism works to explain the root cause of the above phenomenon.
Expect for help!
If possible please explain the root cause of the above phenomenon for me. And, If there is a document / source explaining how the operation of Memory Management 2005-BorlndMM , please send it to me. Thanks you so much!
The problem with your code is that it bypasses string reference counting. By copying the structure using CopyMemory you end up with two variables, both referring to the same string object. But that object still has a reference count of one.
What happens after that is unpredictable. You may encounter runtime errors. Or you may not. The behaviour is not well defined.
From your question you appear to be trying to understand why different memory managers lead to different behaviours. The thing about undefined behaviour is that it is, well, not defined. There's no point trying to reason about the behaviour. It's not possible to reason about it.
You must fix your code by replacing the memory copy with simple assignment:
F1 := Form9.F1;
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.
I'm working with Delphi XE, and writing an application that is using RemObjects SDK to communicate (in case that may be relevant). I have FastMM debug on, and sometimes (not always) when I close it gives a warning about a single "Unexpected Memory Leak". "An unexpected memory leak has occurred. The unexpected small block leaks are: 117-124 bytes: UnicodeString x 1". Very occasionally, I get x2 reported.
Now, my understanding is that Strings are reference counted, and since there is no other object involved to cause the leak, what might be the situation that could cause this to happen? In this StackOverflow question people cannot find a way to make a leak.
If there is no obvious way, then I will download the latest FastMM source (it appears not to be included with the XE source).
[Edit once resolved] The solution to finding this was to install FastMM source, and enable the FullDebugMode to get the stack trace.
When using typed constants and depending on finalization order, it used to be possible for FastMM to report a leak when there really isn't.
FastMM: Leaked memory reported where I believe it shouldn't.
In short, when the FinalizedFirst unit
get's finalized, the SString constant
get's freed. After finalization of the
unit is done, the finalization of
FinalizedLast get's called. In it is
finalization, it call's the method
LeakMemory of the FinalizedFirst
method. The SString variable gets
initialized again and doesn't get
freed as the finalization of
FinalizedFirst has already run.
FinalizedLast Unit
unit FinalizedLast;
interface
uses FinalizedFirst;
implementation
initialization LeakMemory;
finalization LeakMemory;
end.
FinalizedFirst Unit
unit FinalizedFirst;
interface
procedure LeakMemory;
implementation
uses FinalizedLast;
procedure LeakMemory;
const
SString: string = '';
begin
//***** SString will get initialized once or twice depending on the
// finalization order of units. If it get's initialized twice,
// a memory leak is reported.
if SString = '' then
SString := 'FooBar';
end;
end.
Project LeakMemory
program LeakMemory;
uses
FastMM4 in 'FastMM4.pas',
Forms,
FinalizedFirst in 'FinalizedFirst.pas',
FinalizedLast in 'FinalizedLast.pas';
{$R *.RES}
begin
Application.Initialize;
Application.Run;
end.
You can leak strings by freeing records on the heap using FreeMem instead of Dispose or if you overwrite a record using System.Move or FillChar. In the first case the finalization code isn't run and in the second if the string field was filled with a nil it will think it's already cleared it.
If you want to find the location for the leak download FastMM and turn on FullDebugMode. It will include a stack trace of where the leak occurred.
The only way that comes to mind where you can leak a string without deliberately breaking it (like manually incrementing the ref count or doing some messy pointer operation) is by using threadvar.
Like the help file states,
Dynamic variables that are ordinarily
managed by the compiler (long strings,
wide strings, dynamic arrays,
variants, and interfaces) can be
declared with threadvar, but the
compiler does not automatically free
the heap-allocated memory created by
each thread of execution. If you use
these data types in thread variables,
it is your responsibility to dispose
of their memory from within the
thread, before the thread terminates.
Beside that, there's nothing that comes to mind that wasn't already stated.
[Edit by questioner] This was indeed the issue, and the specific code was as follows:
threadvar
g_szAuthentication : String;
procedure TMyBase.SetAuthentication(szUserName, szPassword: String);
begin
g_szAuthentication := '?name=' + szUserName + '&pass=' + szPassword;
end;
I usually see string leaks when they are contained inside other objects that have not been destroyed properly. For example an object that has not been freed. However, you would expect to see that object reported too.
The way to resolve this is to download and use the full version of FastMM and configure it to report stack traces when it detects leaks. When you do that you will get a full stack trace of the code that allocated the leaked object and at that point it is usually clear what the problem is.
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.