project load faster - delphi

I am writing my own text editor, and I was wondering how can I make it load faster. Notepad.exe witch comes with windows loads almost instantly and it is a small application (on XP is 67.5KB), I know that my app is a MDI project, but it has ~900KB and it loads in 5 seconds. I could write a DLL with all bitmaps and load them from there but I don't thing that this is the solution.
Anyone has any ideea?
thanks

In one of my projects I gained a tremendous decrease in loading time by disabling the autocreation of forms. Only the mainform is created in the DPR, all others are created when needed.

Often, it's the perceived speed that's important rather than the actual speed. If you can get a splash screen up as quickly as possible and continue initializing while that's up, people will see that as faster.
Another trick is to put most of your code into DLLs and run your program on Windows startup with a special invisible mode:
myprog.exe /sneaky
which may convince Windows to leave your DLLs in memory so that, next time your application starts, it's faster.
Or even stay running in memory in invisible mode and, when the user runs myprog.exe themselves, simply make yourself visible.
Yet again, use lazy-loading DLLs for the bulk of your functionality (we've used this one under UNIX) so that it's only loaded when needed. This amortizes the loading process over the total execution time rather than taking a big hit at startup.
Those are some tricks I've heard of, there may be others.

All performance problems, can be solved by looking at the code that is executed.
Guessing what is causing the performance problems may have you spinning your wheels for a long time. When you have a performance problem, you need to profile your code. There are various tools for Delphi out there to help you do this.
Some of which are:
Automated AQTime
ProDelphi
Sampling Profiler
These and other options were discussed in this Stack Overflow Question
There are various techniques to speed up code once you have identified what the problem areas are. Since you have identified the area you want to improve, profile the start up of your application.
You may find that your creating things such as forms, resources, or other object that don't need to be created at startup.
Often applications have more than one way they can be started. Since your application is a text editor I suspect you may have a command line where you can specify the file you want to edit. Profiling the different ways you can start your application is key to make sure really know all the impacts of performance improvement.

I noticed that my project loads E_SKU327.dll and E_DAUDF1.dll about 20 times, those files belong to a shared printer (Epson Stylus), so I removed the TPageSetupDialog from my form, and it loads instantly :)
Problem solved
:)

Try to omit the code on the start and initializations sections, and see if there's any improvement, then check which section make your application load slower in this case.
and if you testing the startup time with opening text file, try to replace TMEMO (if you are using it) with SynEdit and it will load the text files a lot faster, even from Notepad ;-).

Related

TWebbrowser massive memory leaks : no solution so far

I have an application that uses TWebbrowser to periodically navigate to a specific URL and extract some data. The app keeps runing 24x7 and does a lot of navigation in pages.
The problem is that TWebbrowser has a well-known memory leak problem, in which every time you navigate to a new page, the memory used for the application is increased. My app can easily use more than 2GB of RAM after some time. And after navigating hundred of times an 'Out of memory' or 'Out of system resources' exception is thrown and the only way to work around it is restarting the application.
The strange thing is FASTMM never shows these leaks. When I use my app for some minutes and close it, nothing is reported.
I've been searching for a solution for this problem for years (in fact since 2007 when I wrote the first version of my application). There are some workarounds but in fact, none of them solves the problem. For me the only workaround is really to close and open the app periodically.
I already tested the SetProcessWorkingSetSize approach, but it only shrinks the memory used by the app temporarily. After some seconds, the app uses a huge amount of memory again.
I also tried EmbeddedWB, but as it descends from TWebbrowser, it's plagued by the same issue.
By the way, I can't use a simple component like IdHTTP, because I need to do some JavaScript manipulation in the website visited.
Does anyone know if is there REALLY a solution for this problem?
QC#106829 describes one possible cause of memory leaks with TWebBrowser. Accessing Document (and any other properties that are implemented via TOleControl.GetIDispatchProp or TOleControl.GetIUnknownProp) causes leaks because it calls AddRef without ever calling Release. As a workaround, you can manually call Release, or you can patch the VCL (see here), or you can avoid the problematic properties (for example, by using browser.DefaultInterface.Document instead of browser.Document).

Hunting down EOutOfResources

Question:
Is there an easy way to get a list of types of resources that leak in a running application? IOW by connecting to an application ?
I know memproof can do it, but it slows down so much that the application won't even last a minute. Most taskmanager likes can show the number, but not the type.
It is not a problem that the check itself is catastrophic (halts the app process), since I can check with a taskmgr if I'm getting close (or at least I hope)
Any other insights on resource leak hunting (so not memory) is also welcomed.
Background:
I've an Delphi 7/2006/2009 app (compiles with all three) and after about a few week it starts acting funny. However only on one of the places it runs, on several other systems it runs till the power goes out.
I've tried to put in some debug code to narrow the problem down. and found out that the exception is EOutofResources on a save of a file. (the file save can happen thousands of times a day).
I have tried to reason out memory leaks (with fastmm), but since the dataflow is quite high (60MByte/s from gigabit industrial camera's), I can only rule out "creeping" memory leaks with fastmm, not quick flashes of memoryleaks that exhaust memory around the time it happens. If something goes wrong, the app fills memory in under half a minute.,
Main suspects are filehandles that are somehow left on some error and TMetafiles (which are streamed to these files). Minor suspects are VST, popupmenu and tframes
Updates:
Another possible tip: It ran fine for two years with D7, and now the problems are with Turbo Explorer (which I use for stable projects not converted to D2009 ).
Paul-Jan: Since it only happens once a week (and that can happen at night), information acquisition is slow. Which is why I ask this question, need to combine stuff for when I'm there thursday. In short: no I don't know 100% sure. I intend to bring the entire Systemtools collection to see if I can find something (because then it will be running for days). There is also a chance that I see open files. (maybe should try to find some mingw lsof and schedule it)
But the app sees very little GUI action (it is an machine vision inspection app), except screen refresh +/- 15/s which is tbitmap stretchdraw + tmetafile, but I get this error when saving to disk (TFileStream) handles are probably really exhausted. However in the same stream, TMetafile is also savetostreamed, something which later apps don't have anymore, and they can run from months.
------------------- UPDATE
I've searched and searched and searched, and managed to reproduce the problems in-vitro two or three times. The problems happened when memusage was +/- 256MB (the systems have 2GB), user objects 200, gdi objects 500, not one file more open than expected ).
This is not really exceptional. I do notice that I leak small amounts of handles, probably due to reparenting frames (something in the VCL seems to leak HPalette's), but I suspect the core cause is a different problem. I reuse TMetafile, and .clear it inbetween. I think clearing the metafile doesn't really (always?) resize the resource, eventually each metafile in the entire pool of tmetafile at maximum size, and with 20-40+ tmetafiles (which can be several 100ks each) this will hit the desktop heap limit.
That's theory, but I'll try to verify this by setting the desktop limit to 10MB at the customers, but it will be several weeks before I have confirmation if this changes anything. This theory also confirms why this machine is special (it's possible that this machine naturally has slightly larger metafiles on average). Occasionally freeing and recreating a tmetafile in the pool might also help.
Luckily all these problems (both tmetafile and reparenting) have already been designed out in newer generations of the apps.
Due to the special circumstances (and the fact that I have very limited test windows), this is going to be a while, but I decided to accept the desktop heap as an example for now (though the GDILeaks stuff was also somewhat useful).
Another thing that the audit revealed GDI-types usage in a thread (though only saving tmetafiles (that weren't used or connected otherwise) to streams.
------------- Update 2.
Increasing the desktop limit only seemed to minorly increase the time till the problem occurred.
Unfortunately, I won't be able to follow up on this further, since the machines were updated to a newer version of the framework that doesn't have the problem.
In summary I can only state what the three core modifications were going from the old to the new framework:
I no longer change screens by reparenting frames. I now work with forms that I hide and show. I changed this since I also had very rare crashes or exceptions (that could be clicked away) due to this. The crashes were all while operating the GUI though, not spontaneously like the main problem
The routine where the crash happened dealt with TMetafile. TMetafile has been designed out, and replace by a simpler own made format. (basically arrays with Opengl vertices)
Drawing no longer happened with tbitmap with a tmetafile overlay strechdrawn over it, but using OpenGL.
Of course it could be something else too, that got changed in the rewrite of the above parts, fixing some very nasty detail bug. It would have to be an extremely bad one, since I analysed the above system as much as I could.
Updated nov 2012 after some private mail discussion: In retrospect, the next step would have been adding a counter to the metafiles objects, and simply reinstantiate them every x * 1000 uses or so, and see if that changes anything. If you have similar problems, try to see if you can somewhat regularly destroy and reinitialize long living resources that are dynamically allocated.
There is a slim chance that the error is misleading. The VCL naively reports EOutOfResources if it is unable to obtain a DC for a window (see TWinControl.GetDeviceContext in Controls.pas).
I say "naively" because there are other reasons why GetDC() might return a NULL handle and the VCL should report the OS error, not assume an out of resources condition (there is a Windows version check required for this to be reliably possible, but the VCL could and should take of that too).
I had a situation where I was getting the EOutOfResources error as the result of a window handle becoming invalid. Once I'd discovered the true problem, finding the cause and fixing it was simple, but I wasted many, many hours trying to find a non-existent resource leak.
If possible I would examine the stack trace leading to this exception - if it is coming from TWinControl.GetDeviceContext then the problem may not be what you think (it's impossible to say what it might be of course, but eliminating the impossible is always the first step toward discovering the solution, no matter how improbable).
If they are GDI handle leaks you can have a look at MSDN Magazine January 2003 which uses the tool GDILeaks. Other tools are GDIObj or GDIView. Also see here.
Another source of EOutOfResources could be that the Desktop Heap is full. I've had that issue on busy terminal servers with large screens.
If there are lots of file handles you are leaking you could check out Process Explorer and have a look at the open file handles of your process and see any out of the ordinary. Or use WinDbg with the !htrace command.
I've run into this problem before. From what I've been able to tell, Delphi may throw an EOutOfResources any time the Windows API returns ERROR_NOT_ENOUGH_MEMORY, and (as the other answers here discuss) Windows may return ERROR_NOT_ENOUGH_MEMORY for a variety of conditions.
In my case, EOutOfResources was being caused by a TBitmap - in particular, TBitmap's call to CreateCompatibleBitmap, which it uses with its default PixelFormat of pfDevice. Apparently Windows may enforce fairly strict systemwide limits on the memory available for device-dependent bitmaps (see, e.g, this discussion), even if your system otherwise has plenty of memory and plenty of GDI resources. (These systemwide limits are apparently because Windows may allocate device-dependent bitmaps in the video card's memory.)
The solution is simply to use device-independent bitmaps (DIBs) instead (although these may not offer quite as good of a performance). To do this in Delphi, set TBitmap.PixelFormat to anything other than pfDevice. This KB article describes how to pick the optimal DIB format for a device, although I generally just use pf32Bit instead of trying to determine the optimal format for each of the monitors the application is displayed on.
Most of the times I saw EOutOfResources, it was some sort of handle leak.
Did you try something like MadExcept?
--jeroen
"I've tried to put in some debug code to narrow the problem down. and found out that the exception is EOutofResources on a save of a file. (the file save can happen thousands of times a day)."
I'm shooting in the dark here, but could it be that you're using the Windows API to (GetTempFileName) create a temp file and you're blowing out some file system indexes or forgetting to close a file handle?
Either way, I do agree that with your supposition about it being a file handle problem. That seems to be the most likely thing given your symptoms and diagnosis.
Also try to check handle count for the application with Process Explorer from SysInternals. Handle leaks can be very dangerous and they build slowly through time.
I am currently having this problem, in software that is clearly not leaking any handles in my own code, so if there are leaks they could be happening in a component's source code or the VCL sourcecode itself.
The handle count and GDI and user object counts are not increasing, nor is anything being created. Deltic's answer shows corner cases where the message is kind of a red-herring, and Allen suggests that even a file write can cause this error.
So far, The best strategy I have found for hunting them down is to use either JCL JCLDEBUG stack tracebacks, or the exception report save features in MadExcept to generate the context information to find out what is actually failing.
Secondly, AQTime contains many tools to help you, including a resource profiler that can keep the links between where the code that created the resources is, and how it was called, along with counts of the total numbers of handles. It can grab results MID RUN and so it is not limited to detecting unfreed resources after you exit. So, run AQTime, do a results capture in mid run, wait several hours, and capture again, and you should have two points in time to compare handle counts. Just in case it is the obvious thing. But as Deltics wisely points out, this exception class is raised in cases where it probably shouldn't have been.
I spent all of today chasing this issue down. I found plenty of helpful resources pointing me in the direction of GDI, with the fact that I'm using GDI+ to produce high-speed animations directly onto the main form via timer/invalidate/onpaint (animation performed in separate thread). I also have a panel in this form with some dynamically created controls for the user to make changes to the animation.
It was extremely random and spontaneous. It wouldn't break anywhere in my code, and when the error dialog appeared, the animation on the main form would continue to work. At one point, two of these errors popped up at the same time (as opposed to sequential).
I carefully observed my code and made sure I wasn't leaking any handles related to GDI. In fact, my entire application tends to keep less than 300 handles, according to Task Manager. Regardless, this error would randomly pop up. And it would always correspond with the simplest UI related action, such as just moving the mouse over a standard VCL control.
Solution
I believe I have solved it by changing the logic to performing the drawing within a custom control, rather than directly to the main form as I had been doing before. I think the fact that I was rapidly drawing on the same form canvas which shared other controls, somehow they interfered. Now that it has its own dedicated canvas to draw on, it seems to be perfectly fixed.
That is with about 1 hour of vigorous testing at least.
[Fingers crossed]

Finding a Memory Bubble

This is either ridiculously simple, or too complex . . . .
In our application there is a form that loads some data from the database and displays it in the grid (putting it simply). When the data is refreshed the total memory usage climbs by about 50K (depending on how much data is displayed no doubt). Sounds like a memory leak, but when we shut down the application, FastMM is set with ReportMemoryLeakOnShutDown := True, and it doesn't report any abnormal memory leaks.
So it appears we have a memory bubble or bag. Something that is accumulating more memory each time it is run. Like a TList that keeps getting new items added to it, but the old ones never get removed. Then in the shutdown process all the items get destroyed. The rows displayed in the grid do not increase, but there are a lot of object lists behind the scenes that make this work, so it could be anywhere.
So my question is if anyone knows of a good trick for finding out what parts of an application are using how much memory . . . . I can think of lots of tedious ways of doing it (which I am in the process of doing - checking each list I can find), so I am hoping someone has a trick or technique I have not thought of.
Thanks in advance!
Update: Every refresh results in an additional 10-50K of memory being used. The users are reporting that eventually the application stops responding. It certainly acts like a memory leak, but FastMM (the memory manager) does not see anything leaking. I'll try some other memory tools . . .
Just F8 through the critical part and look at the process usage graph (Process Explorer from Mark Russinovich works great for that). When you find the culprit method, repeat the process but descend into that method.
Tools like AQTime can report difference in memory/object usage between snapshots. This might help you find out what keeps growing.
It looks like there is some memory allocated via custom AllocMem() calls, bypassing FastMM.
This can be midas. Andreas has a solution for this
Or some other InitXXX WinAPI call that allocates something, without freeing. Or some other third-party or windows dll used by project.
Does this happen every time you refresh the data or only the first time? If it's only the first time it could be that the system just reserves the memory for your application, despite the fact that it's not used at this time. (Maybe at some point the old and new data existed simultaneously in memory?)
There are many tools which provide you with informations about memory leaks, have you tried a different one?
Im not a FastMM expert, but I suppose that after a memory manager get memory, after you free the objects/components, it holds for future use with some zeroes or flag, I dont know, avoiding the need to ask the OS for more memory any time, like a cache.
How about you create the same form/open same data, N times in a row?
Will increase 50K each time?
Once I had the same problem. The application was certainly leaking, but I got no report on shutdown. The reason for this was that I had included sharemem in the uses-section of the project.
Have you tried the full FastMM-version? I have found that tweaking its settings gives me a more verbose information of memory usage.
As Lars Truijens mentioned, AQTime provides a live memory consumption graph, so in runtime, you can see what objects are using more memory whenever you refresh data.

How to Test for Memory Leaks?

We have an application with hundreds of possible user actions, and think about how enhancing memory leak testing.
Currently, here's the way it happens: When manually testing the software, if it appears that our application consumes too much memory, we use a memory tool, find the cause and fix it. It's a rather slow and not efficient process: the problems are discovered late and it relies on the good will of one developer.
How can we improve that?
Internally check that some actions (like "close file") do recover some memory and log it?
Assert on memory state inside our unit tests (but it seems this would be a tedious task) ?
Manually regularly check it from time to time?
Include that check each time a new user story is implemented?
Which language?
I'd use a tool such as Valgrind, try to fully exercise the program and see what it reports.
first line of defense:
check list with common memory
allocation related errors for
developers
coding guidelines
second line of defense:
code reviews
static code analyis (as a part of build process)
memory profiling tools
If you work with unmanaged language (like C/C++) you can efficiently discover most of the memory leaks by hijacking memory management functions. For example you can track all memory allocations/deallocations.
It seems to me that the core of the problem is not so much finding memory leaks as knowing when to test for them. You say you have lots of user actions, but you don't say what sequences of user actions are meaningful. If you can generate meaningful sequences at random, I'd argue hard for random testing. On random tests you would measure
Code coverage (with gcov or valgrind)
Memory usage (with valgrind)
Coverage of the user actions themselves
By "coverage of user actions" I mean statements like the following:
For every pair of actions A and B, if there is a meaningful sequence of actions in which A is immediately followed by B, then we have tested such a sequence.
If that's not true, then you can ask for what fraction of pairs A and B it is true.
If you have the CPU cycles to afford it, you would probably also benefit from running valgrind or another memory-checking tool either before every commit to your source-code repository or during a nightly build.
Automate!
In my company we have programmed an endless action path for our application. The java garbage collector should clean all unused maps and list and something like that. So we let the application start with the endless action path and look, whether the memory use size is growing.
The check which fields are not deleted you can use JProfiler for Java.
Replace new and delete with your custom versions and log every act of allocation/deallocation.
Speaking generally (not about testing, rather to fight the issue in its origin), smartpointers help to avoid this problem. Fortunately, C++11 standard provides new convenient smart pointer classes (shared_ptr, unique_ptr).

How do I go about diagnosing memory corruption errors occurring in a COM-DLL after porting it from Delphi 2007 to Delphi 2009?

I have just ported several of our home-made Outlook COM-addins from Delphi 2007 to Delphi 2009 and am now experiencing some really weird errors (before you ask: none of which appear to have any obvious relationship to string-handling), for example modal dialogs that hang Outlook when one tries to invoke them a second time (the first time around everything appears to be fine) but only when they're invoked from one specific event handler and not when doing the same thing somewhere else. When I trace the error to a specific line of code and comment out that line or replace it with different code to the same effect (e.g. by copying code that would otherwise be called via a function directly to the calling site), the error will appear to go away - typically only to reoccur a couple of (equally inconspicuous looking) statements later.
When running this inside the Delphi debugger I can see that the freezes are often preceded by Access Violations in GetMem.inc . At least all of these issues are 100% reproducible...
Needless to say we had none of these issues when compiling these addins in Delphi 2007.
Now, I'm quite at a loss. I know I have just been lucky but even though I consider myself a fairly experienced programmer (though mostly in niche areas) I never really had to deal with this class of error before. As the title of this question says, I don't even really know where to start. I can step through the code as much as I like but the endless assembler statements mean nothing to me and neither am I proficient in effectively using the CPU view.
Furthermore, I don't even know for sure yet whether this is an issue with my own code to begin with (I actually tend to doubt it in this case). We are makign massive use of a number of third-party libraries (e.g. JCL, ADX, Redemption). ADX in particular still labels its Delphi 2009 support "beta".
I also tried using FastMM's FullDebugMode and indeed I did uncover a number of errors in ADX that way (e.g. blocks that were modified after having been freed) but all of these also occur when I compile with Delphi 2007 so it doesn't yet seem imperative that these are ultimately the cause for the observed regression.
So, how do I deal with this? - or better yet: Where can I find some good resources on learning how to deal with this? e.g. tutorials on using the CPU view or effectively interpreting and acting upon the reports put out by FastMM? Are these the correct tools at all? Where else should I look?
Addendum:
What types of code should I be suspicious of in this context? What kind of code even has the potential to wreak such havoc in memory? The only places I can think of where my code performs anything remotely approaching explicit memory manipulation is when reserving some buffer space in preparation of a WinAPI call. Also keep in mind that all of my code is identical between the Delphi 2007 and Delphi 2009 versions and the Delphi 2007 version exhibits no such problems.
Update:
With some probability the issue that prompted me to post this question has now been solved. See my own answer below.
The best tool for getting to a solution is probably memory breakpoints.
Debugging memory corruption is painful, so try to make your life as simple as possible first: find an exact, guaranteed-reproducible set of steps that work every time. If necessary, mock up the Outlook host so that you don't need to rely on Outlook timing issues or address space layout issues etc.
It's imperative that you get a reliably reproducible set of steps that results in an AV or other error at a predictable address.
What you then do is restart the process, create a memory breakpoint set for whatever referred to that address, and get familiar with the lifecycle of that chunk of memory. Minmizing and rationalizing your reproduction steps helps here. It may help to add other breakpoints and only enable the memory breakpoint later in the application; or use the logging features of D2009 breakpoints to log memory values / call stacks etc., rather than actually breaking into the debuggee.
Not exactly an answer to the question which was more general, but very probably the solution to the specific problem that prompted it:
I am 95% sure to have identified the problem now! :)
Here's what I did:
I enabled RangeChecking and OverflowChecking in the compiler
I tracked down and fixed all problems that caused ERangeError or EIntOverflow exceptions
(there was one of each)
I ran the program again with FastMM and FullDebugMode enabled
I was finally able to identify the cause of the problem in all cases to be a call to the JCL function GetWindowCaption
It seems that GetWindowCaption has obviously not yet been checked for Unicode-compatibility: It was using the value returned from the API function GetWindowTextLength (which returns the number of characters) as input for ReallocMem (which expects the number of bytes) to allocate the buffer for GetWindowText (which in Delphi 2009 returns a buffer of WideChars). Boom! The function was allocating too little memory for the buffer but GetWindowText simply overwrote the following memory thus corrupting the block footer.
I have now filed this in the JCL bug tracker as item #4648
The bottom line I took out of this is: Always be sure to fix all reported errors! Including (seemingly) non-critical ones like range and overflow errors. If nothing else, it will make debugging that much more predictable.
The fact that you catch double-free bugs in D2007, even though it does appear to work fine in this version, means that you NEED to fix those because you are merely lucky that the D2007 version does not need to recycle the memory as aggressively as the D2009 version and the bugs do not show up due to "shadow persistence" in memory.
I would use FastMM fulldebugmode to find the bad code and fix it as much as possible, then follow Barry's advice to trouble shoot memory usage.
For how to use the features of the Integrated Debugger, and how to log info from non breaking breakpoints, you may want to look at this CodeRage 3 session: Delphi Debugging for Dummies
I'd look in direction of full pageheap support built into the system.
Look in this post for how to configure it. Provided your memory usage is not too extensive, this is the easiest to do to find the problem.
It gets tricky when memory consumption is heavier - but like I said, try full peagheap first.

Resources