I'm running Embarcadero RAD Studio 2010 (C++) and have used AQTime a bit to check for some leaks. I wonder if there is a good way to pinpoint the origin in my code of a large amount of threads that seem to never die. They are created during the night so I don't see them as it happens but I would like to be able to go back and see which parts of the code that has generated the most threads and use that information in my detective work.
2 Answers
Is it your code that's creating the threads? If so, you could subclass TThread, (yes, again:), override the ctor to log the threadID of the caller and derive all your other thread classes from that. Obviously, you need a thread-safe logger - you probably already have one.
If the thread ID of the ctor caller is not much help because most of your threads are created from one thread with many creates, (eg. main GUI thread), I guess you could log the caller return address somehow & try and sort out where the call came from. When faced with such a problem, I'm afraid I would take the easy, unclever way out, pass an extra integer ID in the thread constructor and edit my code to pass a different ID on each call. Yes, this is horrible but it works. Someone else surely has a better way. It would have been nice if the standard TThread.create in classes took an extra 'parameter:anObject' to 'pass' into the constructor/thread but, sadly, no :((
I just have to ask, though, why you are creating so many threads? It's fairly rare that I create any thread after app startup, or terminate any before app close, (actually, I don't bother terminating them explicitly on thread close - ExitProcess() does a good job:).
Rgds, Martin

- 24,453
- 3
- 36
- 60
-
This is a legacy server->client solution containing 500.000-1.000.000 lines that I have taken over. Clients connecting and sending "questions" to the server creates threads and so on. The design is kinda strange at places where the server holds gui information for the client which is passed vi TCP connections to the client. – inquam May 31 '11 at 11:36
-
Oh.. a maintenance job :((((( – Martin James May 31 '11 at 12:12
I would try using the Allocation Profiler with only one active area containing only the TTHread class. Start profiling and let it work overnight. When you come in next morning, click Get Results in AQtime. As a result, you will see all TTHread instances in the report, and the Details panel will show the creation call stack for each of them. To minimize the amount of data collected, I would probably set the "Collect stack information" setting of the profiler to "By routines" - this will not give you the line numbers, but this may be a good starting point to find out what happens inside.
If I would need further details, I would use the information collected on the first step to run the app under the Function Trace profiler with the Areas set up in a way when only the rutines I need are included (based on the creation call stacks identified before). This would give me the complete information on the subject.
Read about profiling areas here: http://smartbear.com/support/viewarticle/17895/
And check the profilers descriptions here:
Allocation: http://smartbear.com/support/viewarticle/18030/
Function Trace: http://smartbear.com/support/viewarticle/17971/
Does this suggestion work in your case?

- 587
- 3
- 9
-
I think this would probably be enough to point me in the right direction. Will setup a test run today and see what I get tomorrow. – inquam May 31 '11 at 13:03
-
QQ: Which module would I have to include into AQTime to be able to add TThread? – inquam May 31 '11 at 13:14
-
Seems like it could be found by selecting "classes" and looking in **rtl140.bpl**. But the only thing that seems to get caught is `Module Name Class Name Namespace Token Finalizable Total Created Peak Created Live Count Total Size Peak Size Live Size FOOBAR.EXE Local heap 0 False 18 1 0 10362 8192 0` – inquam May 31 '11 at 13:45
-
I can see the TThread class if I expand the module node in the Modules list, and check the items inside the Classes unit. Don't you see it there? As for the results: select the Objects node in the results tree, not Classes - you will see the individual objects created. Select any of them, and switch to the Details panel (at the bottom of the screen) to see the creation call stack. – Alex May 31 '11 at 17:48
-
BTW, you can read more about the results analysis here: http://smartbear.com/support/viewarticle/18192/ – Alex May 31 '11 at 17:50
-
Just before I packed up for the day I saw that the debug build configuration for the server hadn't been updated to be compatible with AQTime profiling. Will see if I get better results tomorrow. – inquam May 31 '11 at 19:37
-
I have added a **area** and added **TThreads** to it, and compiled every part of the application in debug mode now. But I still only get **VCL Native memory** and **Heap memory** in the result. That doesn't say much about what classes where actually allocated. Any ideas? – inquam Jun 08 '11 at 07:45
-
Found this "... the Allocation does not report the names of classes in Intel C++, Borland C++ and GNU CC applications. The classes in these applications are traced as memory objects and the leaks are included into the C++ native memory class ...". That wasn't what I was hoping for :) – inquam Jun 08 '11 at 09:51
-
Well, it's not that bad :) The quote tells about Borland C++ and not about C++Builder - they are different. The same topic says: "As for classes that reside in Visual C++, Delphi and C++Builder applications, AQtime may or may not trace them as memory blocks. In order for AQtime to be able to trace a class, as a class, not as a memory block, the class must meet certain requirements." And for C++Builder, the requirement is: "The class must have a constructor written in code or generated by the C++ compiler". I believe this is the case for TThread. – Alex Jun 08 '11 at 13:02
-
But it doesn't seem to work anyways :(... It only reports memory. Here it seems to state that this is all I can excpect: http://smartbear.com/support/viewarticle/18252/ – inquam Jun 08 '11 at 13:09
-
This help topic is again about Borland C++, and not about C++Builder. I have just created a very small program with the TMyThread class deriving from TThread, and AQtime was able to detect the TMyThread class object creation, and reported the class name correctly. How do you get the results? Do you close the app to get the report? Or do you click Get Results? How did you set up the profiling areas? Can you try with a small program to check that this works in general? – Alex Jun 08 '11 at 14:01
-
I'm new to Embarcaderos stuff and lived under the impression that RAD Studio 2010 indeed was Borlad C++. I have tried to close the app and clicking `get results`. I have tried with "no" profiling area and a profiling area whick I create with "add new area" and then I drag and drop TThread into that area. I have then tested with only that selected and with that selected alongside `Full Check by Classes`. – inquam Jun 08 '11 at 14:54
-
Using an area with TThread will not work, since your code apparently does not create an instance of this class directly. An instance of a successor class is created instead. So, try adding to the created area the classes that derive from TTHread - you will have to make some searching through the code... When you get the results in any way, check the Classes category in the results (it's in the Explorer panel) - locate the class deriving from TTHread and check the "Total Created" column to see how many instances were created during the run. Do you see your class in the Classes category? – Alex Jun 09 '11 at 08:17
-
I will check to see the exact class instanciated. But if I don't use any area and instead get to see all classes all of them has a count of 0 created and only different memory types are mentioned as created under the .exe and different dlls. – inquam Jun 09 '11 at 09:28
-
Consider adding DLLs to the Modules list of the AQtime project - if the objects creation is performed in a DLL, you need to profile this DLL as well as the host exe. – Alex Jun 09 '11 at 10:01
-
I have already added all the DLL's of the project. But that didn't make any difference. Probably some strange compileflag or something that is missing. Just frustrates me that it just won't work :) – inquam Jun 09 '11 at 10:51
-
Is the default memory manager used in the app, or something like FastMM? (no specific problems with FastMM, just trying to guess what may be different from my simple app where the profiling work). Also, have you already found the class that derives from TThread? Or is it something else that is actually used for threads implementation? – Alex Jun 09 '11 at 11:40
-
The default memory manager is used as far as I can tell. I found out that there are a lot of classes that derives from TThread. Not a very good design in my book. But whatever. So catchning "all" classes is probably the best way to go for me. But since I get none it's still kinda strange. I have even tried creating an area and adding all the classes in my program to it. Still only **Local heap**, **Heap memory** and **VCL native memory**. – inquam Jun 09 '11 at 12:04
-
Check the compiler settings to make sure they match those suggested here: http://smartbear.com/support/viewarticle/18046/ Are the settings correct in the project? Also, are you building with the runtime packages enabled? – Alex Jun 09 '11 at 13:50
-
Well, since I have **RAD Studio 2010** and have followed the settings for that version on their site. But every setting is as in their documentation. The project is build with runtime packages "vclx;vcl;dbrtl;Rave75VCL;bdertl;rtl;bcbie;vclactnband;xmlrtl;bcbsmp;vcldb;vcldbx;dsnap;dsnapcon;teeUI;teedb;tee;adortl;vclib;ibxpress;dbxcds;dbexpress;DbxCommonDriver;IndyCore;IndySystem;IndyProtocols;inet;IntrawebDB_90_100;Intraweb_90_100;vclie;websnap;webdsnap;inetdbbde;inetdbxpress;soaprtl;TranslationTools;FooComponents;dclnet". But the **rtl140.bpl** is added to the setup of **AQTime**. – inquam Jun 10 '11 at 12:07
-
Try adding "C:\windows\system32\rtl150.bpl" to the Modules list - this is what I am adding to make it work. BTW, you can see what exact version of the rtl*.bpl package is loaded by the application by looking at the Event View panel - it lists not only DLLs, but also BPLs. Does it really load rtl140? – Alex Jun 13 '11 at 07:51
-
Yes: `Module Load: rtl140.bpl. No Debug Info. Base Address: $50000000. Process Foo.exe (4676)`. One annoying thing is that the files are not located under "C:\windows\system32" in Windows7. Instead I find them in "./ProgramData/{5D2A2660-61FD-4FE8-A1DB-7338B81FFFF8}/vclwin32runtimes/C8691228/9FAAECB7/rtl140.bpl". It *seems* to be in the *system32* folder but actually isn't. Part of the Windows7 magic folder stuff I think :) – inquam Jun 13 '11 at 07:59
-
Strange... I added the file to the *runtime packages* list an compiled. But AQTime still wanted to add it to the project. But afterwards I finally get to see some class names :)... Thanx for all your time m8. NOW I will profile this piece of cr*p :) – inquam Jun 13 '11 at 08:12