Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations wOOdy-Soft on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Memory leak in VB.net? Need an expert!!!

Status
Not open for further replies.

benlinkknilneb

Programmer
May 16, 2002
590
US
Hey all,

I'm writing a statistical package that pulls information from our plant's database. My reporting mechanism is Crystal. All my data is stored in an Access Database and moved to ADO.NET datasets for intermediate stuff.

I've noticed that my RAM is not being freed after I close down a form. The program has several subsections. When I load one of them, the memory is allocated to hold datasets and stuff, but when I click the 'x' box to close the form, the memory being used by the application does not shrink back to its original size (I'm using the WinNT Task Manager to see this).

In C/C++, any memory allocated with malloc() had to be cleared by using free(), and memory allocated by new had to be freed with delete. Does VB have a stipulation like that? I was under the impression that VB destroyed variables when they went out of scope.
 
.NET is a garbarge-collected language. The memory used by variables that have gone out of scope may not be actually freed until a GC cycle gets run. GC cycles aren't necessarily triggered by a timer (although they may be), usually they're triggered by a request for memory that can't be satisfied, or a hardcoded request (a call to GC.Collect()).

If you're thinking about calling GC.Collect() all over the place - try and restrain yourself. The GC actually does an excellent job in managing memory, and I would just let it do it's job. The thing to avoid is large objects (>85,000 bytes). These don't get compacted during a GC cycle, and you can end up with memory fragmentation.

Chip H.
 
Hey Chip,

Thanks for the quick response. I'm concerned about this because our machines are fairly old, and the databases that I'm pulling from are pretty big in a couple of cases. My supervisor has been testing the project as we go along, and he told me that this morning he got a warning from Windows that he was low on virtual memory. This was after he had run only 3-4 reports. I wondered if there was a way to speed up the garbage collection process, so that ONLY the elements I need remain in memory. I tried adding a GC.Collect() to the main menu, so that each time the user returns there, it would try to collect... I got a little bit of my memory back, but not all of it. Here are the numbers:

Start Program Report Back to Main
With GC 11940K 47024K 39812K
Without 11964K 45100K 45756K

The columns show at what point I checked the value in the memory usage table. What happened to the 27900K in the time between the first time I checked the main menu and returning to the main menu? The running of a subsection is totally unrelated to the running of any other subsections. Can I get any more of that memory back?
 
All free memory isn't actually collected during a GC.Collect. It collects what it believes to be optimal collection. This is often only objects of generation-0 i.e. those that have not survived a collection. Try using the overload GC.Collect(2). This will be slower as it will try to collect all objects but will free more memory if it is available.

Craig
 
Hi Craig,

Thanks for your input. I tried changing it to

GC.Collect(2),

but the program showed almost no improvement over the previous code. The IntelliSense information said that

GC.Collect()

forces a collection of ALL generations, though... so if Collect() wouldn't get it, I wouldn't expect Collect(2) to get it.
 
Hmmm....just noticed something in the original post....

"I've noticed that my RAM is not being freed after I close down a form." Have you set the form to Nothing? If not, it may not garbage collect.

Craig
 
Craig -
That could very well happen - if the form is closed (but not freed), *and* doesn't go out of scope, then the memory will hang around -- probably until the program ends.

benlinkknilneb -
Make sure you set your form variable to Nothing.

Chip H.


 
Hey guys,

Thanks again for the ideas. I was doing a form.dispose(), which seems to be about the same thing... I tried changing it to "Nothing" but it didn't clear any more than before.

Just through little things here and there, I've managed to shrink it a little from the values I posted earlier:

Start Program Report Back to Main
11940K 37408K 30248K

As you can see, it's really good improvement, but still almost 3 times the amount of memory that it should theoretically be... In fact, if I just load and unload the form where the user chooses the options for the report, it jumps to 23000K, none of which disappears when I choose "Back" to return directly to the main menu. I've tried to call dispose() for all of my variables that deal with tables and stuff, you know, the big memory-users... I even tried manually disposing of my data connection, but I'm getting nothing. What am I missing that takes up Megabytes of space?
 
Try running PerfMon -- there are many variables related to memory, and then step through your code to find where the big consumers are.

Chip H.
 
Rereading....this is to do with VIRTUAL memory, not RAM......

Increase the virtual memory on the machine. It is a Windows setting.

Craig
 
Hello again,

Chip - As I expected, the majority of the memory is being allocated for tables and things, usually anywhere from 500K to 1500K per table... I thought I had cleaned up after myself though... I find it a little hard to believe that I would have 10-20 Megabytes of memory out there that I'm not de-allocating.

Craig - Sure, increasing virtual memory would eliminate the warnings and stuff, but I'm looking for a way to keep the memory from being clogged to begin with... also, this program will have to run on several computers in our plant; some of these machines are borderline on Antique and the budget's a little tight right now... so I really want to streamline this thing as best I can, know what I mean?
 
oops ... should have added the following in my code.

Make sure that all objects on the form (especially custom objects) are set to nothing before setting the form to nothing.
 
just a thought.. are you calling the dispose methods on your objects before closing the forms? If not you might want to try that.
 
Derek,
I have no "custom" objects on my forms... do you mean to set *EVERY* object (text boxes, buttons, etc.) to nothing?

Russell,
I've been setting most of the big memory-users to dispose. If you look back through the thread, you'll see that it's made significant improvement. The thing is, I honestly can't believe that I still have 11 MB sitting out there in memory... all I've got is the form and the buttons, boxes, etc. that appear on them... I've "disposed" every data reference I could find.


One idea that I've had to make this thing more efficient is to make each sub-section into a stand-alone module and do something like ShellExecute(). Then, when the section closes, the OS should clear all the memory. Unfortunately, this doesn't fit in the timetable for the plant, so that will have to wait...
 
Not sure if you got this fixed, did you dispose the ado datasets/objects?
 
I have some "dumb" question? Who says that any of the memory that is garbage collected is actually returned to Windows rather than held by Framework for use by future heap allocations inside .Net Framework? Doesn't the Framework acquire a "starting" allocation from Windows for its heap and then get further allocations as the Framework heap needs to expand.? If so, when does the Framework decide to return some memory to Windows as the Framework heap shrinks?

Forms/Controls Resizing/Tabbing Control
Compare Code (Text)
Generate Sort Class in VB or VBScript
 
Gaja:

Yes, I disposed them... at least, all the ones that I manually allocated.

John:

You may be on to something there... I forgot about the framework. My 11MB would be about right for that, wouldn't it?
 
I didn't see anything in your previous messages here to indicate you're using it, but there is a documented memory leak problem with the DataGrid control that Microsoft isn't planning on fixing until the next release of VS.NET.

This problem will manifest itself much the same way as yours (VM grows and doesn't seem to be cleared). It will also cause the processor to spike and stay at 100% for some time. This can occur when a user simply tabs from one cell to the next. Apparently the control creates a number of variables that are not cleaned up by GC. I never go a clear answer from MS on why the processor spiked. So, while it may not have anything to do with your problem, be aware that a like problem exists in the DataGrid.

Oli
 
Oli,

Does it only occur when the user tabs from cell to cell? If so, that's not the problem... but if it can occur with other operations (namely selecting row/s) then you might be on to something there. Thanks for the info!

Ben
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top