Memory Cleanup

  • Thread starter Thread starter Joe
  • Start date Start date
J

Joe

I'm trying to track down where objects are referenced because I want to
clean up the memory when I'm done with them. I thought I found all
references but it doesn't seem that way because calling GC.Collect() doesn't
free very much.

I ran the built-in profiler and I get a warning:
"An abnormal percentage of objects were collected in generation 2, which is
inefficient. Investigate further by using the Objects Lifetime view."

The top 3 generation 2 are:
System.Decimal
System.Int32
System.Runtime.Serialization.ObjectHolder

I don't think there is anything I could do about Decimal and Int32 but what
is the ObjectHolder? I do deserialize data but don't know what I can do to
clean up this object

Thanks,
Joe
 
1) Not generally recomended to call GC.Collect programatically, better to let
runtime determine whens the best time.
2) As part of your trace to see where the memory hog is, you may want to set
your primative types to null when done, and calling dispose/and setting to
null all object you are no longer using. Before explicitly calling dispose.

Best of luck
 
As MMA said, you normally never call GC.Collect. Memory is cleaned up
when needed.

The Decimal and Int32 are both structures, and are only allocated as
objects when they are boxed. That suggests that your program suffers
from a lot of boxing.
 
I call GC.Collect() because memory is not freed as quickly as I need it to
be. I already set my objects to null when I'm done with them but if that
object is still referenced somewhere else, setting the original object to
null will not cause it to be freed.
My best guess is that there is still a reference to these objects somewhere
that wasn't set to null and I have no way of find it without tracing the
object through the entire application.
 
I assume that you previously programmed in an environment having a heap
that uses reference counters and deallocates objects the moment when
there are no more references to it.

The memory management in .NET does not work that way. There are no
reference counters, and nothing happens when objects go out of scope.
The objects just remain in memory waiting for the garbage collector to
remove them.

The garbage collector is only run when needed, which usually happens
when the first generation heap is full. At that time the most of the
objects in the first generation heap are unused, so the garbage
collector just moves the used objects to the second generation, and the
first generation is empty again.

If you force a garbage collection, you will push all the active objects
in the first generation into the second generation, that is why you get
a warning about so many objects being collected in the second generation.

It's normal for a program to accumulate quite some unused objects until
they are collected. That is what makes the memory management efficient.
 
Hi Joe,

I agree that we needn't focus on freeing the memeory we don't need. The
.NET CLR will check if the memoery is low and garbage collection needs to
be performed.

If you really need the memory of an object to be released at once, you can
try to use the using statement in C#. It automatically releases the memory
used to store objects that are no longer required. The release of memory is
non-deterministic; memory is released whenever the CLR decides to perform
garbage collection. However, it is usually best to release limited
resources such as file handles and network connections as quickly as
possible.

GC.Collect just attempts to reclaim all memory that is inaccessible.
However, the Collect method does not guarantee that all inaccessible memory
is reclaimed.

Please check the following link for more information about using statement.

http://msdn2.microsoft.com/en-us/library/yh598w02.aspx

Kevin Yu
Microsoft Online Community Support

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.
Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================

(This posting is provided "AS IS", with no warranties, and confers no
rights.)
 
Kevin said:
If you really need the memory of an object to be released at once, you can
try to use the using statement in C#. It automatically releases the memory
used to store objects that are no longer required.

No it doesn't. The using statement just calls Dispose, which typically
releases unmanaged resources such as file handles etc. It *doesn't*
free any managed memory.

Jon
 
It seems my question is not fully understood. Calling GC.Collect is not the
issue. The issue is that my objects don't get freed.

Take the following:

class A
{
DataTable table;
}

A a = new A();
.... // Do some stuff with class a

a = null;

// Exit method, do other stuff, check memory
// The total memory has not gone down.

When running the profiler is shows that at the time of exit that class A
still had 1 instance alive at end.
Since class A has a DataTable as a member you can image how much resources
this class could take up.

We may at times want to get rid of the original class A and construct
another one so having any of the older class A instances left around isn't
very good.

-Joe
 
Hi Joe,

First, we have to make sure if this object instance is still referenced
after a = null;. If some other references still point to it, it will not be
released. Did you assigned it to some other reference when "Doing some
stuff with class a"?

If after a=null; there is no reference to the a object, we still cannot
force that memory block to be garbage collected. When it is not referenced,
it will only be collected in the next GC action. But when will the GC be
performed depends on CLR. Garbage collector's optimizing engine determines
the best time to perform a collection, based upon the memory allocations
being made. So the profiler might still show that this instance is not
freed even your code goes out of scope.

Please read the following link for more information about Garbage
Collection.

http://msdn2.microsoft.com/en-us/library/0xy59wtx.aspx

Kevin Yu
Microsoft Online Community Support

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.
Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================

(This posting is provided "AS IS", with no warranties, and confers no
rights.)
 
Hi Joe,

I'd like to know if this issue has been resolved yet. Is there anything
that I can help. I'm still monitoring on it. If you have any questions,
please feel free to post them in the community.

Kevin Yu
Microsoft Online Community Support
==================================================

(This posting is provided "AS IS", with no warranties, and confers no
rights.)
 
In case anyone is wondering here is how I fixed the problem:

I removed all calls to GC.Collect() to begin with.
Found a great program called .NET Memory Profiler
(http://memprofiler.com/Default.htm) which showed me where my objects were
being referenced.
Using the profiler I was able to find and null all the references to my
objects to free them. I was still left with an issue that even though there
were no more references the memory was still allocated. I put one call to
GC.Collect() in and that took care of it.

Now all my allocated memory that I expect to be freed is.

Thanks everyone that replied.
Joe
 
Joe said:
In case anyone is wondering here is how I fixed the problem:

I removed all calls to GC.Collect() to begin with.
Found a great program called .NET Memory Profiler
(http://memprofiler.com/Default.htm) which showed me where my objects were
being referenced.
Using the profiler I was able to find and null all the references to my
objects to free them. I was still left with an issue that even though there
were no more references the memory was still allocated. I put one call to
GC.Collect() in and that took care of it.

Now all my allocated memory that I expect to be freed is.

It's rarely a good idea to call GC.Collect() in production code though.
It's nice to use it under a profiling session just to check that
something really *is* eligible for garbage collection, but normally the
garbage collector does the right thing in a reasonably efficient
manner.

It *can* be worth calling GC.Collect() when you've finished a large
body of work and you know that there will be a lot of garbage, but even
then I'd test it carefully to see whether it helps.
 
Jon,

I understand that it's not good practice to call GC.Collect() but we have at
times 300-800 megs of ram allocated that need to be cleaned up and the GC
doesn't clean it quick enough.

-Joe
 
| Jon,
|
| I understand that it's not good practice to call GC.Collect() but we have
at
| times 300-800 megs of ram allocated that need to be cleaned up and the GC
| doesn't clean it quick enough.
|

But this is not possible, the GC run more often than you think he is, if
your memory goes up that much without going down fast enough is because you
are still holding references to allocated objects. The GC can only collect
garbage. Just look at the CLR-Memory performance counters using perfmon, but
please remove these GC.Collect calls, they only disturb the normal behavior
of the GC, really.

Willy.
 
Joe said:
Jon,

I understand that it's not good practice to call GC.Collect() but we have at
times 300-800 megs of ram allocated that need to be cleaned up and the GC
doesn't clean it quick enough.

Quick enough for what?

If the memory is needed for anything, the GC will run.
 
Back
Top