Solved

TCollection crashes intermittently (don't you hate that word?)

Posted on 2002-06-04
17
193 Views
Last Modified: 2010-04-04
I have a certain window created at run-time.  In this window is a table that serves as a master for many other tables on the form.  All tables on this form have, as their DatabaseName property, the name of a database component that's in a database module which belongs to the project.  To me, that seems like a normal thing to do.

*Sometimes* when I close the window, the form crashes.  I have delved deep into the Delphi code several times to try and find the bug.  It turns out that a TCollection, of type TFieldDefs, is crashing when it frees one of its FItems, a TFieldDef.  I can, by reason, find out which of the TFields in the TDataSet crashed, but I can't find out WHY!  Oh, and sometimes it's a different table and a different field...

The program continues to run semi-normally.  Closing the program produces more errors, but starting the program again gets the user back on his/her feet.

The good news is that, luckily, none of the data in the tables on the form is ever lost.  However, no more windows of that type can be created at run-time.  An error appears saying that a component by the same name cannot be created.  I've tried circumventing this side-effect to no avail.  I want to nail the problem at its heart anyway, not treat the symptoms.

Since I do not explicitly free any objects that belong to the form, I don't think I'm at fault.  In fact, my call stack confirms this plea of Not Guilty: every call in the stack is a Delphi-packaged source file.  Objects are properly freeing their ancestors before themselves, and they free their children components.  Nothing seems wrong.  Something must be freeing a lonely TFieldDef on accident.  Maybe?

Also, at design-time I have no TFieldDefs.  They must be being created at run-time by the datasets.

What can I do to stop my form from crashing?
0
Comment
Question by:Pummel
  • 6
  • 3
  • 3
  • +3
17 Comments
 
LVL 27

Expert Comment

by:kretzschmar
ID: 7054864
if you mean with close a window,
did you mean you free a form?

if so, use the release method for this job or
set the action-parameter in the onclose-event of the form to cafree

just guessing

meikl ;-)
0
 
LVL 12

Expert Comment

by:Lee_Nover
ID: 7055042
I've had similar problems regarding dbs

try to set the bound controls DataSource to nil and the DataSources DataSet to nil
that helped me, hope it helps you also :)
0
 

Author Comment

by:Pummel
ID: 7055058
kretzschmar,
Well, I don't release the form manually, either.  When I create it, I hand the Application object in as its owner.  The user closes it using the Windows X button on the title bar.  I don't call that function.

I do, however, handle the OnClose and OnDestroy events, freeing up stuff I created with no parent, and asking the user if they want to make any changes and so forth.

Lee_Nover
If I set those things to nil, then I won't have any data-bound controls!  The user wouldn't be able to see or add things to the database.  How did that kind of solution work for you?
0
 
LVL 1

Expert Comment

by:bes67
ID: 7055307
Hi

I want to ask what database is used (I mean Paradox, Oracle or something else). And try to test following aspects:
- creation order of your forms and datamodule (you have to make your datamodule to be created before any form)
- test field names - probably you use a reserved word
- try to close Datasets explicity (for example in OnClose event handler)

Hope this will help
0
 
LVL 12

Expert Comment

by:Lee_Nover
ID: 7055424
>> *Sometimes* when I close the window, the form crashes <<

set those datasources and datasets to nil when you close the form :)
eg. on the OnClose or OnDestroy event
0
 
LVL 6

Expert Comment

by:swift99
ID: 7055429
It sounds like it is trying to free components that have already been freed.  Since freeing a component does not automatically overwrite its memory, sometimes freeing it again will work.  However, since Windows or the VCL may snag that freed memory for their own uses between the free operations, the operation will fail randomly.

Freeing an object does not remove its references from collections or overwrite the value.  Since an object reference is implemented as a pointer, the main error detection/prevention tool is if Assigned (x).  The Assigned function simply tests to see if the pointer is NIL ... it does not confirm that the memory referenced by the pointer is in fact properly and currently allocated to the current process.

If the TFieldDefs are owned by the form and contained by the TDataset, then it is likely that both the form and the dataset are trying to free them.  Make sure that the owner of the TFieldDefs is the dataset.

Also, I have found event loops are sometimes culprits.  Check your call stack and see if you are in an event loop.  This usually happens when you try to do something that the VCL does for you already.
0
 
LVL 6

Expert Comment

by:swift99
ID: 7055438
Lee: Setting the object references to NIL leaves you at risk of not freeing them correctly.  It may mask the bug, but it will not necessarily resolve it.  I've inherited a project that was built on the philosophy of hiding the symptoms, and I am still finding coding errors two years later.  :o)
0
 
LVL 27

Accepted Solution

by:
kretzschmar earned 444 total points
ID: 7055448
>It sounds like it is trying to free components that have
>already been freed

no, it sounds more like that a try of freeing the form is done and this is canceled by exception, therefore this object can't recreated

>An error appears saying that a component by the
>same name cannot be created

hint, instead of freeing the runtime-created objects in the ondestroy event, free it in the onclose-event with try / except

also keep in mind that runtime-created objects may included in somewheres-componentlist (or any other list),
so that it may be that someone tries to free an already freed object

meikl ;-)
0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 

Author Comment

by:Pummel
ID: 7067587
bes67,
Here are the concerns you addressed, in your original order:
1. The database I'm using is an AS/400.  I connect through an alias listed in the BDE Administrator.
2. I have verified that the creation order is how it should be.  The DataModule is created first.  The form in question is only created at run-time; there is no var variable in the form's unit.
2a. On another note, here is how I create my non-visual components creation order:
Master table
Master datasource
Detail table
Detail datasource
(the last two repeat for all dependent datasources)
In this way, details will be destroyed first.
3. In my department, we have a habit of naming fields in a very weird way.  Every field name starts with 'DP', and to my knowledge, no reserved words start this way.
4. Before I even posted this question, I had tried closing the datasets explicitly in both the OnClose, OnDestroy, and in an overridden Destroy method.  None of these ideas have worked unfortunately.

swift99,
As I mentioned earlier, I do not explicitly free anything.  I let the form do it all.  Testing for nil and who the owners are seems unproductive if the same process is going to try and free that memory again.

But, as I had not officially tried this approach, I decided to give it a shot.  The form crashed when I set FieldDefs to nil, right after calling the Free method.  So, I took out the nil, and left the Free.  The form still crashed.

kretzschmar,
I think we're both right on your first point.  I still think that more than one object is freeing a TFieldDef, but you're also right about the form not entirely closing when an exception occurs.  Since the window is not entirely done away with when an exception occurs, it makes sense that another window can't be created AND it makes sense why the application crashes on exiting, since it's still trying to get rid of the problem form.

While I was writing this reply, I also fiddled with the StoreDefs property.  The only thing that changed was which TFieldDef was crashing.  But then again, that always changes.

Any other ideas?
0
 

Author Comment

by:Pummel
ID: 7070790
Should I use a TSession component, or make one at run-time?  Currently, I just use the default, implicit Session object.  All of the tables on the form have, as their DatabaseName property, the name of a database on the main TDataModule of the program.

Since there can be more than one of these forms open at run-time, would it be wise to instantiate a sessions component?  And how?
0
 

Author Comment

by:Pummel
ID: 7078504
This error, which I have had for months, was fixed by systematically removing components and code from the form until I could not longer get it to crash.  This took a while since sometimes, 50 closes were required before the crash would occur.

The culprit was a TShellListView component on one of the tabs of the form.  It must be using up resources that the TTable had legally acquired.  After restoring my form to its original state (by using a backup) and removing just that component, my program has proceeded to run without crashing when closing the form.  I've closed over 100 forms and no crashes.
0
 
LVL 6

Expert Comment

by:swift99
ID: 7083689
Good detective work.  I guess you get your points back   :o)
0
 
LVL 14

Expert Comment

by:DragonSlayer
ID: 7091982
wow that must've been a real tough bug to find huh
0
 
LVL 12

Expert Comment

by:Lee_Nover
ID: 7092502
yeah .. painfull debugging :)
0
 
LVL 27

Expert Comment

by:kretzschmar
ID: 7092528
just to say the same, as the others above ;-)

glad you get it sort out
0
 

Author Comment

by:Pummel
ID: 7092592
swift99,
I get my points back?  I've deleted other questions before and I continue to see them in my Asked Questions list with the status "PendingDelete".  I haven't paid enough attention to my notes, though.

DragonSlayer, Lee_Nover, and kretzschmar,
It took me three to four days to find.  Every time I'd remove a component, of course, I had to remove any code that referenced it.  Since I thought this was a database issue, I deleted little pieces at a time.  I even deleted tables from my database module, figuring that might be the problem.

After I deleted everything related to the database, including data-aware components (but not the four main master-detail tables), I started to delete other components unrelated to the database.  That's how I found it.  The TShellListView was one of those first non-database components I deleted.

As I debugged, sometimes I'd only have to open the form once or twice and it would crash as usual.  Other times I remember it crashing after more than 50 successive opens and closes.  After I had removed the TShellListView component, I opened and closed more than 100 windows without a crash.  I could only assume the problem was fixed.  Then I restored my old form and took out the TShellListView.  I haven't had any problems since!
0
 

Author Comment

by:Pummel
ID: 7383678
I want to free myself of these points and your answer was the closest to the solution.
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

Introduction The parallel port is a very commonly known port, it was widely used to connect a printer to the PC, if you look at the back of your computer, for those who don't have newer computers, there will be a port with 25 pins and a small print…
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
Sending a Secure fax is easy with eFax Corporate (http://www.enterprise.efax.com). First, Just open a new email message.  In the To field, type your recipient's fax number @efaxsend.com. You can even send a secure international fax — just include t…
Access reports are powerful and flexible. Learn how to create a query and then a grouped report using the wizard. Modify the report design after the wizard is done to make it look better. There will be another video to explain how to put the final p…

743 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

15 Experts available now in Live!

Get 1:1 Help Now