On my project, I am using inherited MDIChild forms from base form. My problem is about memory management. After release forms ( by FreeAndNil) with FormClose events, Delphi still keep on memory and do not release.
What should I do for that? MDI management different or what?
I doubt it has something to deal with the children Forms, even when you terminate an application with several children forms open Delphi will free them without memory leaks.
To get a hint of what's going on, at your Source Project's code insert this,
Begin
ReportMemoryLeaksOnShutdown:= DebugHook <> 0;
…
end.
Run the application in the IDE, do something you usually do then close the application. Delphi will inform you the memory leaks it encounters and a hint of what it is.
I always use above line in my applications, when testing (debugging), Delphi informs about memory leaks on shutdown.
Related
Running 11.1, I get this TGPUObjectsPool error on shutting down a simple basic FMX 2D app under Windows 64-bit (Release mode). First time I have seen this error.
Just running a blank form with ReportMemoryLeaksOnShutdown := True in project.dpr results in this error on closing.
There are no components on the TForm. Just run and close. It makes me wonder what kind of QA is done for a Delphi release if a basic empty project can close with such memory leaks.
Any solutions to get rid of this error?
---------------------------
Unexpected Memory Leak
---------------------------
An unexpected memory leak has occurred. The unexpected small block leaks are:
9 - 24 bytes: TGPUObjectsPool x 1
89 - 104 bytes: TObjectDictionary<System.TClass,System.Generics.Collections.TObjectList<FMX.TextLayout.GPU.TReusableObject>> x 1
It makes me wonder what kind of QA is done for a Delphi release
A lot, actually. Months of beta testing, lots of fixes and internal builds.
This issue was actually reported during testing, but only just a couple of weeks ago, after it was too late to fix for the final release. But, this leak (and others) have been reported publicly after 11.1 was released:
RSP-37596 FMX TFontGlyphManager's UnInitialize not called in finalization
RSP-37600 Unexpected Memory Leak in TGPUObjectsPool
RSP-37613 Memory leak in an application that only serves forms
RSP-37656 Memory leak in FMX (simple project)
And there are other similar memory leaks (in TFontGlyphManager, TBehaviorServices, etc), so hopefully this will get fixed in the next update.
I guess maybe they should consider having their samples include the ReportMemoryLeaksOnShutdown=True.
Funny, because I see a similar report for that, too:
RSP-37598 Make RTL, FMX and VCL developers turn on memory leak checking by default
I fixed it (as a workaround) including ShareMem as first unit in uses in my project source.
Try this:
uses
{$IFDEF VER350} // 11.x
FMX.FontGlyphs, FMX.TextLayout.GPU,
{$ENDIF}
finalization
{$IFDEF VER350} // 11.x
// RAD Studio 11 memory leak
TFontGlyphManager.UnInitialize;
TGPUObjectsPool.Uninitialize;
{$ENDIF}
I have used FastMM and it is a great tool to detect leaks and memory problems.
But now I try to check a COM Server made with Delphi, and the reports are not consistent.
I have tried to configure FastMM in the DLL with ShearMM and others, but I am aware that this should not be the case (the COM server must be a black box isolated from the binary that uses it, that is NOT to share the MM).
So ... How should I configure it?
What defines should I enable in the server project so that FastMM reports leaks on the COM server?
EDITED
I add a delphi project as an example. It consists of a COM in-proc object with a leak and an EXE project that consumes it, also with a leak. When executing the client, only FastMM4 shows report by the client leak. Server leak is not detected (or not reported):
Delphi Sample
A curiosity: in the server, if instead of FastMM, I use the Delphi leaks report (ReportMemoryLeaksOnShutdown), the server leak is found by Delphi!
Another clarification: my FastMM4Options.inc is untouched, as it comes in FastMM4 sources
If you configure your COM object to run in an out-of-process server process, so that a creation of your COM object starts your EXE file, you should be free to use FastMM, isolated from the calling process as you describe.
If the EXE-file is started by COM in this way, by default it will terminate when the last object is released, unless you override this behaviour with the ComServer.OnLastRelease event (ComServer is declared in the System.Win.ComServ.pas unit).
Situation:
a DLL that:
is written and compiled with Delphi XE3 32bit
exports a function that displays a modal VCL-form:
function EditOptions(AIniFileName: PAnsiChar; ALCID: Integer): Boolean; stdcall;
is also a COM-server
an installer created with InnoSetup 5.5.4:
imports said DLL function via external 'EditOptions#files:mydll.dll stdcall'-directive and calls it when needed
explicitly unloads the DLL before registering the COM server via the Inno utility function UnloadDLL
Problem:
When...
Windows is using a theme other than Classic
the modal dialog from the DLL is displayed during installation
the installer hangs upon unloading the DLL
no error messages are shown
logs indicate no runtime exceptions
Please note that to keep this brief, I deliberately left out the explanations for some of the more idiosyncratic details, e.g. why I'm explicitly unloading the DLL or why a COM server needs to have custom exports. Let me know if you think these details would be relevant and should be added.
To further analyse this I created a dummy host EXE that calls the DLL function so I can easier run the whole thing in the debugger. Doing so leads to an AV being raised in TUxThemeStyle.UnloadThemeData on the line that calls CloseThemeData(). When placing a breakpoint directly on that line and stepping forward from the stop, I actually get a "too many consecutive exceptions" error eventually. I can only reproduce the error when I enable runtime themes for the host EXE.
Going back through our git history it appears that this issue exists ever since we switched from Delphi 2010 to XE3 (unfortunately, the installer was not part of our regular test suite so this only cropped up now as work on the actual release comes to a close as the DLL exports exist exclusively for the benefit of the installer).
Any ideas what might be causing this? Could this really be theme-related (I have no custom theme-related code in this project) or is that maybe just a symptom of memory corruption caused somewhere else entirely? E.g. I once had an error that manifested in the form of AVs in the theme tear-down code before but in that case it actually turned out to be caused by the leaking of anonymous method references from initialization sections...
Update: I've worked hard trying to produce a dumbed-down sample project to demonstrate the issue in isolation but so far without luck. I have managed to narrow down a few more things, though. First, here are some more facts about the code:
The dialog I'm showing is a third-degree descendant of TForm. The ancestors accomplish several things:
TAppModalDialog implements a special constructor CreateOnTop that ensures it appears as the topmost window in the current process (the project is a plugin that loads into multi-windowed third-party hosts that do unfortunately not communicate their window handles for use as modal parents) - it accomplishes this by manipulating the global Application.Handle.
TTabbedDialog is part of an interface-based framework that allows registration of "pages" (actually TFrame-descendants) via a factory pattern - at runtime the form will dynamically create TTabSheets in a TPageControl and instantiate and parent the registered page frames to them
I've replaced the call to the actual dialog with a dummy, gradually working myself through the inheritance chain from a blank TForm up to my TAppModalDialog and eventually to my TTabbedDialog class. The problem only starts to occur at that last level. I also commented out all page registrations around the project so that the dialog comes up with an empty page control (this rules out code in any of the pages as the cause for the problem). I then commented out all code and data members in the routines of the TTabbedDialog class itself, leaving only empty method bodies to fulfill the interface implementation requirement and the TPageControl component (along with two empty TImageLists and a TBalloonHint component) -> the error still occurs.
I then copied the call to the dummy dialog into a new DLL project that contains nothing else but this and the tabbed dialog framework. If I load that DLL into my dummy host EXE, the problem does not occur anymore... sigh
So, my suspicion is still that there must be some sort of memory corruption occuring somewhere else entirely and the error I see is only a symptom of that. So the real question is how can I finally get to the bottom of this?
I will now continue by commenting out / removing bits from the production DLL...
This is occurring on 2 machines that are both running Windows XP Pro SP3, yet it runs OK on my development machine within in or outside the Delphi IDE.
Running Windows XP Pro. Exe compiled under Delphi 2010.
When I run the exe I get the Windows Reporting error "Neopos.exe has encountered a problem and needs to close. We are sorry for the inconvenience"
I know it is happening somewhere in the form create of the main form.
Application.Initialize; //Runs this
Application.CreateForm(TfmMain, fmMain); //FAILS HERE
It does not get to: procedure TfmMain.FormCreate(Sender: TObject); in the Main Form and I don't know how to track down this error and debug it.
What happens between: Application.CreateForm(TfmUDF, fmUDF); AND procedure TfmMain.FormCreate(Sender: TObject) in my main form.
How can I trace this to find out what the hell is causing the Windows Error.
Of course the Windows Error report contains a long listing of information. Where can I look in that to find the cause or at least a clue on the cause of the error.
This error has now stopped all development work (and ruined my weekend) so I urgently need to fix this.
The most straightforward route to take would be to include a product like MadExcept or JCL Debugger into your application, to get a full call stack (including line number) of the point of failure. We've rolled our own years ago, and it has been a tremendous help in situations like this.
One alternative, but lots more cumbersome, would be to generate a MAP file from your project, use MAP2DBG to generate a .MAP file, and use the Windows Debbuging Tools to get about the same information. This approach is a lot more hardcore, and only advisable if you really want to learn a lot about the internals of windows debugging (and enjoy working with arcane tools).
Another alternative would be to attach to the failing application from your development environment using Remote Debugging. Only applicable if you have a fair amount of control over the failing machines.
#user576639, here are some debugging ideas:
Look into the System's Event Viewer
If you got the exe has encountered a problem and needs to close chances are you'll find something about it in the System's Event Viewer. That should be your first step.
Any special DLL's required?
Do you need MIDAS.DLL?
Are you using an database engine? Does it require some sort of client library?
I'm talking from experience here: My development machine obviously has all the libraries I might need. Most of my clients also have most of those libraries because they have my software installed. At times I put out small helping applications that don't go throw extensive testing and they fail to work on SOME machines but work fine on other machines. Why? I used TClientDataset and forgot to include MIDAS.DLL with the application; Or the application is trying to access a Firebird SQL server but the user doesn't have Firebird client library installed.
Printer driver issues
Boy I hate Delphi's printer handling. Also hate buggy printer drivers, haven't made up my mind about what's worst. If you have something on your main form that might be requesting information about the default Windows printer (example: an REPORT) give this a try: Install an sane/simple printer and set it as the default printer. If the user has Office 2007+ installed, set the "Microsoft XPS Document Writer" the default printer.
I have seen bad printer driver + delphi issues manifest themselves with the "exe needs to close" symptom.
Prepare an special build of your application
If you got this far without fixing your issue it's time to create an special build of your application that's capable of providing more information. First of all I'd try adding this to your DPR file; Don't know if this is still useful for Delphi 2010 but it did help me see some early exceptions with a Delphi 7 application:
function HandleUnhandledException:integer;stdcall;
begin
Result := 1; // 1 = EXCEPTION_EXECUTE_HANDLER
end;
// and then immediately after "begin" in your DPR file:
begin
SetUnhandledExceptionFilter(#HandleUnhandledException);
// ... the usual stuff goes here
end;
Add some ShowMessage-s to your Main Form's code, in your OnCreate handler (if you have one), in your Create constructor (again, if you have one). If you're adding an ShowMessage to your Create destructor, make sure it's after the "inherited" call. This will help pin-point how far the loading of the form goes before it fails.
If all else fails...
Create a new, blank form; Make it the new Main Form (so it's initialized before your former Main Form). Test it on the client's machine - does it show up? It most likely will, if it doesn't you've got some serious problems.
Start copying the components from the former main form to the new main form; Only the components need to be copied, not the code: Your error is probably caused by some component failing to initialize properly. Make sure no component has "Active=True"! Copy the components in small batches, test often. If you spot the component that causes your form not to load on the client's computer, tell us about it and we'll try to help.
If you manage to get all your components on the new form, write an OnCreate handler that sets Active := True for all the components that need that. Did that fix the issue?
If you got this far then all the components you used on your main form can load properly. The problem's related to YOUR CODE. Start copying all the code from your old main form to your new main form, in small bits, and test. You're bound to find the peace of code that causes your application to stop loading.
Use dependency walker to see if you're missing a required DLL.
You can use information from system reporting (your error and suggestion to send it ) with Error Report Grabber ( http://www.maxerist.net/main/soft-for-win/err-rep-grabber ). I developed this tool when I desperately needed to track a error that appeared very rarely so almost non-reproducible. It helped me to track the information from stack to find actual place in the code.
The tool works only on XP (MS removed this dialog in Win7 and probably Vista), but I see that your cases are XP so this can help.
UPDATE: if you're not familiar with assembler and everything, this can work like this.
You should compile you program and don't change anything. Save the report on a bad machine, copy the file to your developer machine and open to view the contents. Look at the stack of your main thread in the report and find numbers more than $00400000, they're usually the addresses inside the procedures that called some other procedure and wait for return. In your developer machine, start the program and stop at any line, open CPU Window and on the main list with assembler instruction right-click and choose go to address, enter this address. You will see other assembler lines, but wrapped with pascal constructions you can probably recognize as yours
Thanks a lot for the help.
In the end I reverted to a recent backup and traced it down to a particular form.
I did not actually find the error, which is a bit worrying, but in any case I am back up and running (phew!!)
I made the error to occur on my development machine also, when, and only when, I use my install program (Inno Setup) to compile a setup.exe and which installs the exe as well as installing postgreSQL. Seems really strange, as though there is a problem with the setup compiler. In any case I have not seen the error again. I guess it will remains a mystery, like women.
In Delphi withing debugging options select debug dcu's, this will allow you to debug into the Delphi source code for TForm and its descendants and you may be able to track down a more likely culprit.
Set a breakpoint on
Application.CreateForm(TfmMain, fmMain); //FAILS HERE
and then step into the code to see where the issue is.
I have a small program which simply reads a diary text file and displays it in a memo - thats it - no buttons you double click on the form to shut it down if you want it to disappear. When it has been run (even if you close it) windows XP gets as far as "Windows is shutting down" ie. after "Saving User Settings" etc and then it hangs. I have examined the code which appears little different from other programs I have written which were much more complicate but can see nothing wrong - the close routine for example contains application.terminate which (I think) should clear anything wrong out of memory anyway. Any ideas since I seem to have run out of them?
Based on what you've described, the program should have a single line of programmer-added code, which is to call Memo1.Lines.LoadFromFile. That's what it means when you say, "That's it."
That program doesn't even need a "close routine." (I assume you mean the form's OnClose event.) When the main form closes, the application terminates itself automatically. That's how all Delphi programs work. If you're putting more on top of that, you're doing too much.
Just a few suggestions, because it is not entirely clear what your problem is.
Does your application has problems with closing, or does it hang during windows shutdown?
Have you tried putting a breakpoint on application.Terminate? And does that provide extra information.
From within the mainform, you can use Close and not Application.Terminate.
Apps can inhibit shutdown if they are using up CPU time, although a 'modern' OS like Vista and W7 should show a dialog telling you about this after a period and offering to let you abort the app. Check that your app is showing 0% CPU when its idle by looking in task manager and viewing 'processes'.
Bri
The following code reacts on the windows shutdown message und closes the program.
TForm1 = class(TForm)
...
private
procedure WMEndSession(var Message: TWMEndSession); message WM_ENDSESSION;
...
end;
procedure TForm1.WMEndSession(var Message: TWMEndSession);
begin
close;
end;