I'm implementing Windows 10 Notification in my application. However, the code below (which runs fine) apparently give a memo leak of 1 TNotification object and 2 strings, yet I free the object at the end of the block:
aNotification := NotificationCenter.CreateNotification;
//-- If not assigned then must be Win 8.1 or below
if not assigned(aNotification) then
exit;
try
aNotification.Title := AlignMixVersionName + ' License';
aNotification.AlertBody := aText;
NotificationCenter.PresentNotification(aNotification);
finally
aNotification.Free;
end;
Am I doing something stupid or is there a memory leak in the implementation of Notifications?
Steve
It is indeed a leak caused by TNotificationCenterDelegateActivated. In its Create a copy of the TNotification parameter is created, but never freed.
Seems like some developers responsible for this code are not that proficient with non-ARC environments.
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.
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.
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.
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.
I am troubleshooting a problem with existing code that always worked fine (it's the Terminal Server unit from the Jedi Windows Security Library).
After some investigation the problem part has been brought down to a call to WTSOpenServer:
while true do
begin
hServer := WTSOpenServer(PChar('server'));
WTSCloseServer(hServer);
hServer := 0;
end;
After a random (but small) number or runs we get a total app crash which makes it hard to debug.
Here are the things I already tried:
WTSOpenServer does not write to the pServername parameter (like CreateProcessW) (in fact I checked the disassembly and it makes a copy)
The code runs fine when passing nil as parameter (and thus work with the localmachine).
When using a remote server, localhost or even dummy as pServerName the result is always crash (On Vista and higher even an invalid servername returns a valid handle as per documentation).
Tested with both Delphi 2009 and 2010
The same code runs fine in Visual Studio (c++).
Checked the disassembly in Visual Studio and made the call the WTSOpenServer in asm from Delphi (and change the Handle type to a pointer like in C):
hModule := LoadLibrary('wtsapi32.dll');
if hModule = 0 then
Exit;
WTSOpenServer := GetProcAddress(hModule, 'WTSOpenServerW');
if WTSOpenServer = nil then
Exit;
while true do
begin
asm
push dword ptr pServerName;
call dword ptr WTSOpenServer;
mov [hServer], eax;
end;
hServer := nil;
end;
Leave out the call to WTSCloseServer
Test the code on both x64 and x86 version of Windows 7
Use External Debugger instead of Delphi one (seems to run fine in that case so my guess is that it's some kind of timing/thread/deadlock issue)
Added AddVectoredExceptionHandler then I see a EXCEPTION_ACCESS_VIOLATION but the stacks seems to be corrupted, EIP is 1 so cannot determine where it happens.
At this point I don't know how to further troubleshoot this or find an explanation.
Try run your application with FastMM in FullDebugMode. It looks more like a bug in your/3rd party-lib code - possible memory overwrite/buffer overflow (moslty like sth. GetMem too small for UnicodeString/String alike operations, and it 'works' but will sooner or later crash/AV).
I've had several similar situations when migrating big app to D2009, and in most cases it was due to assumption Char=1 byte. Sometimes very strange things happened, but always FullDebugMode helped. Exception was CreateProcessW, but it's know/documented behaviour.
With FullDebugMode if app overwrite memory, then when you free it, FastMM gives you exception where it was allocated, so easly you can track down this bug. It adds some bytes at begining and end of allocation, so will know if it was overwritten.
I'm not able to reproduce it with new/empty VCL project, you can try it your self (this loop running for about 5 min):
uses JwaWtsApi32;
procedure TForm7.FormCreate(Sender: TObject);
var
hServer: DWORD;
begin
while true do
begin
hServer := WTSOpenServer(PChar('server'));
WTSCloseServer(hServer);
hServer := 0;
end;
end;