By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
440,304 Members | 3,201 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 440,304 IT Pros & Developers. It's quick & easy.

Not axactly a memory leak but can be bad

P: n/a

I finally narrowed down my code to this situation, quite a few (not all) of
my CMyClass objects got hold up after each run of this function via the
simple webpage that shows NumberEd editbox. My memory profile shows that
those instances survive 3 rounds of GC collections - it's not what I
expected. In my real code, CMyClass occupies big amount of memory and they
all share one stance of another class that I don't have enough memory hold
more than a just a few in the memory. Notice that the finalizaer the my
CMyClass makes a big difference in demonstrating this issue, w/o it the
problem doesn't exist. The interesting thing is if I run the page again,
the old dangling ones got destroyed and the new ones become dangling. Am I
missing something about the GC? Do I need to explicitly implement and call
dispose for these classes instead of relying on GC to promptly collect it?
Apparently somehow these objects can survive the automatic
collections...disposing it would help. Thanks for your comment and help.

internal class CMyClass
{
ArrayList m_array = new ArrayList( 50000 );
private string m_idStr;
private Guid m_guid;
internal CMyClass( int n )
{
for( int i = 0; i < n; ++i )
m_array.Add( Guid.NewGuid() );

m_guid = Guid.NewGuid();
m_idStr = m_guid.ToString();
}

internal Guid id
{
get{ return (Guid ) m_array[ 0 ]; }
}

~CMyClass()
{
// Trace.Write( m_guid, m_idStr );
}

}
private void RunBtn_Click(object sender, System.EventArgs e)
{
ResultEd.Text = "";
try
{

for( int i = 0; i < int.Parse( NumberEd.Text ); ++i )
{

Hashtable table = new Hashtable( 100 );
ArrayList ids = new ArrayList( 10 );
for( int j = 0; j < 10; ++j )
{
Guid id = Guid.NewGuid();
table[ id ] = null;
ids.Add( id );
}
for( int k=0; k < 10; ++k )
{
foreach( Guid id in ids )
{
table[ id ] = new CMyClass( 10 );
}

CMyClass myobj;
foreach( Guid id in ids )
{
myobj = (CMyClass) table[ id ];
myobj.id.ToString();
}
} // for k
} // for
}
catch( Exception ex )
{
ResultEd.Text = ex.Message + "...CallSTack:" +
ex.StackTrace;
}

GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();

GC.WaitForPendingFinalizers();
GC.Collect();

ResultEd.Text = "Done";
}

Nov 17 '05 #1
Share this Question
Share on Google+
25 Replies


P: n/a
Zeng wrote:
the finalizaer the my
CMyClass makes a big difference in demonstrating this issue, w/o it the
problem doesn't exist.


Actually, the finalizer is the problem. When the GC detects that an
object with a finalizer is garbage, it "resurrects" it and puts it on
a finalization queue, to be finalized by a background thread. When the
finalization thread actually gets to call finalize and remove your
object from the queue, the object is again available for collection.
Of course, it's (probably) now been bumped a generation, and so will
stick around for a while.

// Jon, who's procrastinating a bit today ....

--

www.midnightbeach.com
Nov 17 '05 #2

P: n/a

"Zeng" <Ze******@hotmail.com> wrote in message
news:%2****************@TK2MSFTNGP09.phx.gbl...

I finally narrowed down my code to this situation, quite a few (not all)
of
my CMyClass objects got hold up after each run of this function via the
simple webpage that shows NumberEd editbox. My memory profile shows that
those instances survive 3 rounds of GC collections - it's not what I
expected. In my real code, CMyClass occupies big amount of memory and
they
all share one stance of another class that I don't have enough memory hold
more than a just a few in the memory. Notice that the finalizaer the my
CMyClass makes a big difference in demonstrating this issue, w/o it the
problem doesn't exist.


Why do you have a finalizer in the first place, classes having finalizers
need at least two sweeps to be collected.

Willy.
Nov 17 '05 #3

P: n/a


"Willy Denoyette [MVP]" wrote:
Why do you have a finalizer in the first place, classes having finalizers
need at least two sweeps to be collected.


The main reason IMO is CYA when unmanaged resources are involved. The
intent should always be to use Dispose to clean them up asap but if you
forget, or the person who has to maintain your code a year after you've left
doesn't realize he needs to, finalize will make sure it's cleaned up
eventually.
Nov 17 '05 #4

P: n/a

"Dan Neely" <Da******@discussions.microsoft.com> wrote in message
news:0B**********************************@microsof t.com...


"Willy Denoyette [MVP]" wrote:
Why do you have a finalizer in the first place, classes having finalizers
need at least two sweeps to be collected.


The main reason IMO is CYA when unmanaged resources are involved. The
intent should always be to use Dispose to clean them up asap but if you
forget, or the person who has to maintain your code a year after you've
left
doesn't realize he needs to, finalize will make sure it's cleaned up
eventually.


I know, but in this case the CMyClass class doesn't implement IDisposable,
doesn't hold any unmanaged resouces and has a completely redundant empty
Finalizer.

Willy.


Nov 17 '05 #5

P: n/a
Is there a way to force the collection on those objects with a finalizer?
From all the documentation I've been reading (not enough reading)
GS.Collect() would do it, then I found some place that calling Collect()
then call WaitForPendingFinalizers() then Collect() again would do it, now I
found that it doesn't do it either. Disposing would just help freeing memory
from unmanaged resources, if all the stuff that occupy memory are in the
managed classes, it would be a problem w/o a way to force collection.


"Jon Shemitz" <jo*@midnightbeach.com> wrote in message
news:43**************@midnightbeach.com...
Zeng wrote:
the finalizaer the my
CMyClass makes a big difference in demonstrating this issue, w/o it the
problem doesn't exist.


Actually, the finalizer is the problem. When the GC detects that an
object with a finalizer is garbage, it "resurrects" it and puts it on
a finalization queue, to be finalized by a background thread. When the
finalization thread actually gets to call finalize and remove your
object from the queue, the object is again available for collection.
Of course, it's (probably) now been bumped a generation, and so will
stick around for a while.

// Jon, who's procrastinating a bit today ....

--

www.midnightbeach.com

Nov 17 '05 #6

P: n/a
Zeng wrote:
Is there a way to force the collection on those objects with a finalizer?
Why do you want to? (Fwiw, we usually want to avoid finalization,
because resurrection (and memory use that's higher than necessary for
longer than necessary) is not free. This is the point of IDisposable
and the "using" statement. Write a finalizer to do any necessary
cleanup, in case someone forgets to call Dispose; and call
GC.SuppressFinalize in the Dispose() routine, to avoid finalization
costs.)
if all the stuff that occupy memory are in the
managed classes, it would be a problem w/o a way to force collection.


"Would be"? Or "is"? Some very bright people worked very hard on the
garbage collector - it works awfully well, and you almost never need
to "force" it to do anything.

--

www.midnightbeach.com
Nov 17 '05 #7

P: n/a
I wouldn't need to force it if I know for sure that they will be collected
before the asp.net process gets recycled because it reaches maximum % of
memory in the system (the default is 60%). Does anybody know for sure?
thanks!

"Jon Shemitz" <jo*@midnightbeach.com> wrote in message
news:43***************@midnightbeach.com...
Zeng wrote:
Is there a way to force the collection on those objects with a
finalizer?
Why do you want to? (Fwiw, we usually want to avoid finalization,
because resurrection (and memory use that's higher than necessary for
longer than necessary) is not free. This is the point of IDisposable
and the "using" statement. Write a finalizer to do any necessary
cleanup, in case someone forgets to call Dispose; and call
GC.SuppressFinalize in the Dispose() routine, to avoid finalization
costs.)
if all the stuff that occupy memory are in the
managed classes, it would be a problem w/o a way to force collection.


"Would be"? Or "is"? Some very bright people worked very hard on the
garbage collector - it works awfully well, and you almost never need
to "force" it to do anything.

--

www.midnightbeach.com

Nov 17 '05 #8

P: n/a

"Zeng" <Ze******@hotmail.com> wrote in message
news:uI**************@TK2MSFTNGP14.phx.gbl...
I wouldn't need to force it if I know for sure that they will be collected
before the asp.net process gets recycled because it reaches maximum % of
memory in the system (the default is 60%). Does anybody know for sure?
thanks!


Yes, for sure the GC runs more often that you ever imagine.

Willy.
Nov 17 '05 #9

P: n/a
and just to add my two pennies worth ...

Although you may call GC.Collect(), much the same as in Java when you try to
force the VM to run garbage collection, it will still run at it's earliest
convenience.

During compilation, your code is injected with "safe points" whereby the GC
can hijack the thread and take control to do its work. Now, when you call
GC.Collect() your code might not be in a stable enough state for the GC to
run, and the only way that the GC can know that it is safe to run is if it
has reached a "safe point".

Generally speaking, it is bad practice to call GC.Collect() since you will
inadvertantly interrupt a perfectly (or near to) working system, and you
yourself can cause all sorts of naughtiness to occur.

My choice of preference (as it is for a lot of developers) is to implement
IDisposable.

AND, yes, our code should be easily readable and left in a state that
renders it possible for future devlopers to look at it and see what is going
on (for maintenance reasons, or whatever), however, designing our classes
"off centre" just in case, the next developer doesn't know as much as us is a
pretty poor choice IMHO.

--
Of all words of tongue and pen, the saddest are: "It might have been"

Bill.Richards @ greyskin .co .uk
http://greyskin.co.uk
"Zeng" wrote:

I finally narrowed down my code to this situation, quite a few (not all) of
my CMyClass objects got hold up after each run of this function via the
simple webpage that shows NumberEd editbox. My memory profile shows that
those instances survive 3 rounds of GC collections - it's not what I
expected. In my real code, CMyClass occupies big amount of memory and they
all share one stance of another class that I don't have enough memory hold
more than a just a few in the memory. Notice that the finalizaer the my
CMyClass makes a big difference in demonstrating this issue, w/o it the
problem doesn't exist. The interesting thing is if I run the page again,
the old dangling ones got destroyed and the new ones become dangling. Am I
missing something about the GC? Do I need to explicitly implement and call
dispose for these classes instead of relying on GC to promptly collect it?
Apparently somehow these objects can survive the automatic
collections...disposing it would help. Thanks for your comment and help.

internal class CMyClass
{
ArrayList m_array = new ArrayList( 50000 );
private string m_idStr;
private Guid m_guid;
internal CMyClass( int n )
{
for( int i = 0; i < n; ++i )
m_array.Add( Guid.NewGuid() );

m_guid = Guid.NewGuid();
m_idStr = m_guid.ToString();
}

internal Guid id
{
get{ return (Guid ) m_array[ 0 ]; }
}

~CMyClass()
{
// Trace.Write( m_guid, m_idStr );
}

}
private void RunBtn_Click(object sender, System.EventArgs e)
{
ResultEd.Text = "";
try
{

for( int i = 0; i < int.Parse( NumberEd.Text ); ++i )
{

Hashtable table = new Hashtable( 100 );
ArrayList ids = new ArrayList( 10 );
for( int j = 0; j < 10; ++j )
{
Guid id = Guid.NewGuid();
table[ id ] = null;
ids.Add( id );
}
for( int k=0; k < 10; ++k )
{
foreach( Guid id in ids )
{
table[ id ] = new CMyClass( 10 );
}

CMyClass myobj;
foreach( Guid id in ids )
{
myobj = (CMyClass) table[ id ];
myobj.id.ToString();
}
} // for k
} // for
}
catch( Exception ex )
{
ResultEd.Text = ex.Message + "...CallSTack:" +
ex.StackTrace;
}

GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();

GC.WaitForPendingFinalizers();
GC.Collect();

ResultEd.Text = "Done";
}

Nov 17 '05 #10

P: n/a
Relying on IDisposable won't work easily in the multi-threading scenarios.
Since the memory required for each object is big, I have put them on static
variable to share it among the servicing threads. Think of CMyClass is a
spell-grammar-checker that helps looking up things and provide suggestions
for correction for many users create their documents online. In this
scenario, looks like there is the only choice
--> Make CMyClass disposable and create managing component (internal or
external to the class) just to coordinate when and which objects are done
just to call Dispose. This sounds like the intensive plumbing and
error-prone approach that I was so used to with C++

Conceptually, this is the drawback of a smart system, the programmer knows
what he/she needs to be done but can't change its behavior (which is very
very smart most of the time)

By the way, where can I find a documentation about the safe-points?
Wouldn't that be better that there is a call to wait for the system to be
done with collection and there is a safe point in that method? And is there
a safe point in the component that checks for memory usage and recycle the
aspnet process when 60%(default) is reached?

"billr" <bi***@discussions.microsoft.com> wrote in message
news:3B**********************************@microsof t.com...
and just to add my two pennies worth ...

Although you may call GC.Collect(), much the same as in Java when you try to force the VM to run garbage collection, it will still run at it's earliest
convenience.

During compilation, your code is injected with "safe points" whereby the GC can hijack the thread and take control to do its work. Now, when you call
GC.Collect() your code might not be in a stable enough state for the GC to
run, and the only way that the GC can know that it is safe to run is if it
has reached a "safe point".

Generally speaking, it is bad practice to call GC.Collect() since you will
inadvertantly interrupt a perfectly (or near to) working system, and you
yourself can cause all sorts of naughtiness to occur.

My choice of preference (as it is for a lot of developers) is to implement
IDisposable.

AND, yes, our code should be easily readable and left in a state that
renders it possible for future devlopers to look at it and see what is going on (for maintenance reasons, or whatever), however, designing our classes
"off centre" just in case, the next developer doesn't know as much as us is a pretty poor choice IMHO.

--
Of all words of tongue and pen, the saddest are: "It might have been"

Bill.Richards @ greyskin .co .uk
http://greyskin.co.uk
"Zeng" wrote:

I finally narrowed down my code to this situation, quite a few (not all) of my CMyClass objects got hold up after each run of this function via the
simple webpage that shows NumberEd editbox. My memory profile shows that those instances survive 3 rounds of GC collections - it's not what I
expected. In my real code, CMyClass occupies big amount of memory and they all share one stance of another class that I don't have enough memory hold more than a just a few in the memory. Notice that the finalizaer the my CMyClass makes a big difference in demonstrating this issue, w/o it the
problem doesn't exist. The interesting thing is if I run the page again, the old dangling ones got destroyed and the new ones become dangling. Am I missing something about the GC? Do I need to explicitly implement and call dispose for these classes instead of relying on GC to promptly collect it? Apparently somehow these objects can survive the automatic
collections...disposing it would help. Thanks for your comment and help.

internal class CMyClass
{
ArrayList m_array = new ArrayList( 50000 );
private string m_idStr;
private Guid m_guid;
internal CMyClass( int n )
{
for( int i = 0; i < n; ++i )
m_array.Add( Guid.NewGuid() );

m_guid = Guid.NewGuid();
m_idStr = m_guid.ToString();
}

internal Guid id
{
get{ return (Guid ) m_array[ 0 ]; }
}

~CMyClass()
{
// Trace.Write( m_guid, m_idStr );
}

}
private void RunBtn_Click(object sender, System.EventArgs e)
{
ResultEd.Text = "";
try
{

for( int i = 0; i < int.Parse( NumberEd.Text ); ++i )
{

Hashtable table = new Hashtable( 100 );
ArrayList ids = new ArrayList( 10 );
for( int j = 0; j < 10; ++j )
{
Guid id = Guid.NewGuid();
table[ id ] = null;
ids.Add( id );
}
for( int k=0; k < 10; ++k )
{
foreach( Guid id in ids )
{
table[ id ] = new CMyClass( 10 );
}

CMyClass myobj;
foreach( Guid id in ids )
{
myobj = (CMyClass) table[ id ];
myobj.id.ToString();
}
} // for k
} // for
}
catch( Exception ex )
{
ResultEd.Text = ex.Message + "...CallSTack:" +
ex.StackTrace;
}

GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();

GC.WaitForPendingFinalizers();
GC.Collect();

ResultEd.Text = "Done";
}

Nov 17 '05 #11

P: n/a
Again, you don't have to implement IDisposable when you don't deal with
managed resources. What do you expect to do in your Dispose method? And No
there is no documentation available on Safe points, because they don't apply
here (at least not in the code snip you've posted).
I'm also not clear on what you mean with recycling the asp.net process, is
this something you intend to do or is it something that you are expecting to
be done automatically, anyway before the asp.net process recycles, all
application domains get unloaded, and this implies a GC run and a finalizer
run, so all objects (still referenced too) will be collected , but even when
some objects aren't collected, all memory once allocated for the process
will return to the OS when the process ends. So what are you afraid of?
Willy.

"Zeng" <Ze******@hotmail.com> wrote in message
news:uX**************@tk2msftngp13.phx.gbl...
Relying on IDisposable won't work easily in the multi-threading scenarios.
Since the memory required for each object is big, I have put them on
static
variable to share it among the servicing threads. Think of CMyClass is a
spell-grammar-checker that helps looking up things and provide suggestions
for correction for many users create their documents online. In this
scenario, looks like there is the only choice
--> Make CMyClass disposable and create managing component (internal or
external to the class) just to coordinate when and which objects are done
just to call Dispose. This sounds like the intensive plumbing and
error-prone approach that I was so used to with C++

Conceptually, this is the drawback of a smart system, the programmer knows
what he/she needs to be done but can't change its behavior (which is very
very smart most of the time)

By the way, where can I find a documentation about the safe-points?
Wouldn't that be better that there is a call to wait for the system to be
done with collection and there is a safe point in that method? And is
there
a safe point in the component that checks for memory usage and recycle the
aspnet process when 60%(default) is reached?

"billr" <bi***@discussions.microsoft.com> wrote in message
news:3B**********************************@microsof t.com...
and just to add my two pennies worth ...

Although you may call GC.Collect(), much the same as in Java when you try

to
force the VM to run garbage collection, it will still run at it's
earliest
convenience.

During compilation, your code is injected with "safe points" whereby the

GC
can hijack the thread and take control to do its work. Now, when you call
GC.Collect() your code might not be in a stable enough state for the GC
to
run, and the only way that the GC can know that it is safe to run is if
it
has reached a "safe point".

Generally speaking, it is bad practice to call GC.Collect() since you
will
inadvertantly interrupt a perfectly (or near to) working system, and you
yourself can cause all sorts of naughtiness to occur.

My choice of preference (as it is for a lot of developers) is to
implement
IDisposable.

AND, yes, our code should be easily readable and left in a state that
renders it possible for future devlopers to look at it and see what is

going
on (for maintenance reasons, or whatever), however, designing our classes
"off centre" just in case, the next developer doesn't know as much as us

is a
pretty poor choice IMHO.

--
Of all words of tongue and pen, the saddest are: "It might have been"

Bill.Richards @ greyskin .co .uk
http://greyskin.co.uk
"Zeng" wrote:
>
> I finally narrowed down my code to this situation, quite a few (not
> all) of > my CMyClass objects got hold up after each run of this function via the
> simple webpage that shows NumberEd editbox. My memory profile shows that > those instances survive 3 rounds of GC collections - it's not what I
> expected. In my real code, CMyClass occupies big amount of memory and they > all share one stance of another class that I don't have enough memory hold > more than a just a few in the memory. Notice that the finalizaer the my > CMyClass makes a big difference in demonstrating this issue, w/o it the
> problem doesn't exist. The interesting thing is if I run the page again, > the old dangling ones got destroyed and the new ones become dangling.
> Am I > missing something about the GC? Do I need to explicitly implement and call > dispose for these classes instead of relying on GC to promptly collect it? > Apparently somehow these objects can survive the automatic
> collections...disposing it would help. Thanks for your comment and
> help.
>
> internal class CMyClass
> {
> ArrayList m_array = new ArrayList( 50000 );
> private string m_idStr;
> private Guid m_guid;
> internal CMyClass( int n )
> {
> for( int i = 0; i < n; ++i )
> m_array.Add( Guid.NewGuid() );
>
> m_guid = Guid.NewGuid();
> m_idStr = m_guid.ToString();
> }
>
> internal Guid id
> {
> get{ return (Guid ) m_array[ 0 ]; }
> }
>
> ~CMyClass()
> {
> // Trace.Write( m_guid, m_idStr );
> }
>
> }
> private void RunBtn_Click(object sender, System.EventArgs e)
> {
> ResultEd.Text = "";
> try
> {
>
> for( int i = 0; i < int.Parse( NumberEd.Text ); ++i )
> {
>
> Hashtable table = new Hashtable( 100 );
> ArrayList ids = new ArrayList( 10 );
> for( int j = 0; j < 10; ++j )
> {
> Guid id = Guid.NewGuid();
> table[ id ] = null;
> ids.Add( id );
> }
>
>
> for( int k=0; k < 10; ++k )
> {
> foreach( Guid id in ids )
> {
> table[ id ] = new CMyClass( 10 );
> }
>
> CMyClass myobj;
> foreach( Guid id in ids )
> {
> myobj = (CMyClass) table[ id ];
> myobj.id.ToString();
> }
> } // for k
> } // for
> }
> catch( Exception ex )
> {
> ResultEd.Text = ex.Message + "...CallSTack:" +
> ex.StackTrace;
> }
>
> GC.Collect();
> GC.WaitForPendingFinalizers();
> GC.Collect();
>
> GC.WaitForPendingFinalizers();
> GC.Collect();
>
> ResultEd.Text = "Done";
> }
>
>
>
>


Nov 17 '05 #12

P: n/a
I'm not sure on what you mean by "there is no documentation
available...because they don't apply here...". The existance of a document
doesn't depend on what part of version of my code was posted. I appreciate
your help looking into this for me, many people would just ignore posts and
move on even they know the answer or have some comments, but I don't think
we are going anywhere with it. My response was to BillR who proposes that I
should be implementing the IDisposable.

It's the production environment, if the process get recycled, all my cache
in the memory will have to be reloaded when it goes back up. That would
cause delay to the service that we want to provide. Sounds like you are not
familiar with the processModel entry with attribute memoryLimit="60" as
default, it's in the machine.config file. thanks!
"Willy Denoyette [MVP]" <wi*************@telenet.be> wrote in message
news:O5*************@TK2MSFTNGP15.phx.gbl...
Again, you don't have to implement IDisposable when you don't deal with
managed resources. What do you expect to do in your Dispose method? And No
there is no documentation available on Safe points, because they don't apply here (at least not in the code snip you've posted).
I'm also not clear on what you mean with recycling the asp.net process, is this something you intend to do or is it something that you are expecting to be done automatically, anyway before the asp.net process recycles, all
application domains get unloaded, and this implies a GC run and a finalizer run, so all objects (still referenced too) will be collected , but even when some objects aren't collected, all memory once allocated for the process
will return to the OS when the process ends. So what are you afraid of?
Willy.

"Zeng" <Ze******@hotmail.com> wrote in message
news:uX**************@tk2msftngp13.phx.gbl...
Relying on IDisposable won't work easily in the multi-threading scenarios. Since the memory required for each object is big, I have put them on
static
variable to share it among the servicing threads. Think of CMyClass is a
spell-grammar-checker that helps looking up things and provide suggestions for correction for many users create their documents online. In this
scenario, looks like there is the only choice
--> Make CMyClass disposable and create managing component (internal or
external to the class) just to coordinate when and which objects are done just to call Dispose. This sounds like the intensive plumbing and
error-prone approach that I was so used to with C++

Conceptually, this is the drawback of a smart system, the programmer knows what he/she needs to be done but can't change its behavior (which is very very smart most of the time)

By the way, where can I find a documentation about the safe-points?
Wouldn't that be better that there is a call to wait for the system to be done with collection and there is a safe point in that method? And is
there
a safe point in the component that checks for memory usage and recycle the aspnet process when 60%(default) is reached?

"billr" <bi***@discussions.microsoft.com> wrote in message
news:3B**********************************@microsof t.com...
and just to add my two pennies worth ...

Although you may call GC.Collect(), much the same as in Java when you try
to
force the VM to run garbage collection, it will still run at it's
earliest
convenience.

During compilation, your code is injected with "safe points" whereby
the GC
can hijack the thread and take control to do its work. Now, when you
call GC.Collect() your code might not be in a stable enough state for the GC
to
run, and the only way that the GC can know that it is safe to run is if
it
has reached a "safe point".

Generally speaking, it is bad practice to call GC.Collect() since you
will
inadvertantly interrupt a perfectly (or near to) working system, and you yourself can cause all sorts of naughtiness to occur.

My choice of preference (as it is for a lot of developers) is to
implement
IDisposable.

AND, yes, our code should be easily readable and left in a state that
renders it possible for future devlopers to look at it and see what is

going
on (for maintenance reasons, or whatever), however, designing our classes "off centre" just in case, the next developer doesn't know as much as us is a
pretty poor choice IMHO.

--
Of all words of tongue and pen, the saddest are: "It might have been"

Bill.Richards @ greyskin .co .uk
http://greyskin.co.uk
"Zeng" wrote:

>
> I finally narrowed down my code to this situation, quite a few (not
> all)

of
> my CMyClass objects got hold up after each run of this function via
the > simple webpage that shows NumberEd editbox. My memory profile shows

that
> those instances survive 3 rounds of GC collections - it's not what I
> expected. In my real code, CMyClass occupies big amount of memory and they
> all share one stance of another class that I don't have enough memory

hold
> more than a just a few in the memory. Notice that the finalizaer
the my
> CMyClass makes a big difference in demonstrating this issue, w/o it
the > problem doesn't exist. The interesting thing is if I run the page

again,
> the old dangling ones got destroyed and the new ones become dangling.
> Am

I
> missing something about the GC? Do I need to explicitly implement and

call
> dispose for these classes instead of relying on GC to promptly

collect it?
> Apparently somehow these objects can survive the automatic
> collections...disposing it would help. Thanks for your comment and
> help.
>
> internal class CMyClass
> {
> ArrayList m_array = new ArrayList( 50000 );
> private string m_idStr;
> private Guid m_guid;
> internal CMyClass( int n )
> {
> for( int i = 0; i < n; ++i )
> m_array.Add( Guid.NewGuid() );
>
> m_guid = Guid.NewGuid();
> m_idStr = m_guid.ToString();
> }
>
> internal Guid id
> {
> get{ return (Guid ) m_array[ 0 ]; }
> }
>
> ~CMyClass()
> {
> // Trace.Write( m_guid, m_idStr );
> }
>
> }
> private void RunBtn_Click(object sender, System.EventArgs e)
> {
> ResultEd.Text = "";
> try
> {
>
> for( int i = 0; i < int.Parse( NumberEd.Text ); ++i )
> {
>
> Hashtable table = new Hashtable( 100 );
> ArrayList ids = new ArrayList( 10 );
> for( int j = 0; j < 10; ++j )
> {
> Guid id = Guid.NewGuid();
> table[ id ] = null;
> ids.Add( id );
> }
>
>
> for( int k=0; k < 10; ++k )
> {
> foreach( Guid id in ids )
> {
> table[ id ] = new CMyClass( 10 );
> }
>
> CMyClass myobj;
> foreach( Guid id in ids )
> {
> myobj = (CMyClass) table[ id ];
> myobj.id.ToString();
> }
> } // for k
> } // for
> }
> catch( Exception ex )
> {
> ResultEd.Text = ex.Message + "...CallSTack:" +
> ex.StackTrace;
> }
>
> GC.Collect();
> GC.WaitForPendingFinalizers();
> GC.Collect();
>
> GC.WaitForPendingFinalizers();
> GC.Collect();
>
> ResultEd.Text = "Done";
> }
>
>
>
>



Nov 17 '05 #13

P: n/a
Sorry what I meant was ""there is no documentation ... AND they don't apply
here". If you need more info on GC safe points I'm afraid you'll have to
look in the source code files of the CLR if you happen to have a Source Code
License. Anyway, when your code calls GC.Collect it's always at a safe GC
point, it's only when a GC is "induced" that it might get postponed when
your code is not at a GC safe point.
What Billr proposed makes little sense in your case because your class don't
own unmanaged resources, like DB connections, unmanaged memory OS handles
etc..., it only consumes managed heap memory which is taken care of by the
GC, there is no need to force collections by calling GC.Collect yourself.
But if you really think you have to implement IDisposable, go ahead, but
please tell us what you will do in your Dispose method.

I guess I'm more familiar with the process model than you might think. The
asp.net hosting process recycles when it's Working Set exceeds the
memoryLimit% of total available memory, but the hosting process will try to
survive first by forcing a full GC run, followed by an attempt to reduce the
working set, then and ONLY when it's WS still exceeds the MemoryLimit% it
will recycle, else it simply continues to run.
In case the WS could not be reduced it's simply because an application
hosted in asp.net allocates too much memory or as a result of heap
fragmentation (take care when allocating many large objects (>85Kb)), or as
a result of a design error.
When it happens on a production system, it must be considered an application
error , because the memoryLimit%, available system memory, number of active
clients etc.. should have been defined during staging, when you performed
your load/stress testing and your workload modeling.

Willy.

"Zeng" <Ze******@hotmail.com> wrote in message
news:%2****************@TK2MSFTNGP09.phx.gbl...
I'm not sure on what you mean by "there is no documentation
available...because they don't apply here...". The existance of a
document
doesn't depend on what part of version of my code was posted. I
appreciate
your help looking into this for me, many people would just ignore posts
and
move on even they know the answer or have some comments, but I don't think
we are going anywhere with it. My response was to BillR who proposes that
I
should be implementing the IDisposable.

It's the production environment, if the process get recycled, all my cache
in the memory will have to be reloaded when it goes back up. That would
cause delay to the service that we want to provide. Sounds like you are
not
familiar with the processModel entry with attribute memoryLimit="60" as
default, it's in the machine.config file. thanks!
"Willy Denoyette [MVP]" <wi*************@telenet.be> wrote in message
news:O5*************@TK2MSFTNGP15.phx.gbl...
Again, you don't have to implement IDisposable when you don't deal with
managed resources. What do you expect to do in your Dispose method? And
No
there is no documentation available on Safe points, because they don't

apply
here (at least not in the code snip you've posted).
I'm also not clear on what you mean with recycling the asp.net process,

is
this something you intend to do or is it something that you are expecting

to
be done automatically, anyway before the asp.net process recycles, all
application domains get unloaded, and this implies a GC run and a

finalizer
run, so all objects (still referenced too) will be collected , but even

when
some objects aren't collected, all memory once allocated for the process
will return to the OS when the process ends. So what are you afraid of?
Willy.

"Zeng" <Ze******@hotmail.com> wrote in message
news:uX**************@tk2msftngp13.phx.gbl...
> Relying on IDisposable won't work easily in the multi-threading scenarios. > Since the memory required for each object is big, I have put them on
> static
> variable to share it among the servicing threads. Think of CMyClass is
> a
> spell-grammar-checker that helps looking up things and provide suggestions > for correction for many users create their documents online. In this
> scenario, looks like there is the only choice
> --> Make CMyClass disposable and create managing component (internal or
> external to the class) just to coordinate when and which objects are done > just to call Dispose. This sounds like the intensive plumbing and
> error-prone approach that I was so used to with C++
>
> Conceptually, this is the drawback of a smart system, the programmer knows > what he/she needs to be done but can't change its behavior (which is very > very smart most of the time)
>
> By the way, where can I find a documentation about the safe-points?
> Wouldn't that be better that there is a call to wait for the system to be > done with collection and there is a safe point in that method? And is
> there
> a safe point in the component that checks for memory usage and recycle the > aspnet process when 60%(default) is reached?
>
>
>
> "billr" <bi***@discussions.microsoft.com> wrote in message
> news:3B**********************************@microsof t.com...
>> and just to add my two pennies worth ...
>>
>> Although you may call GC.Collect(), much the same as in Java when you try > to
>> force the VM to run garbage collection, it will still run at it's
>> earliest
>> convenience.
>>
>> During compilation, your code is injected with "safe points" whereby the > GC
>> can hijack the thread and take control to do its work. Now, when you call >> GC.Collect() your code might not be in a stable enough state for the
>> GC
>> to
>> run, and the only way that the GC can know that it is safe to run is
>> if
>> it
>> has reached a "safe point".
>>
>> Generally speaking, it is bad practice to call GC.Collect() since you
>> will
>> inadvertantly interrupt a perfectly (or near to) working system, and you >> yourself can cause all sorts of naughtiness to occur.
>>
>> My choice of preference (as it is for a lot of developers) is to
>> implement
>> IDisposable.
>>
>> AND, yes, our code should be easily readable and left in a state that
>> renders it possible for future devlopers to look at it and see what is
> going
>> on (for maintenance reasons, or whatever), however, designing our classes >> "off centre" just in case, the next developer doesn't know as much as us > is a
>> pretty poor choice IMHO.
>>
>> --
>> Of all words of tongue and pen, the saddest are: "It might have been"
>>
>> Bill.Richards @ greyskin .co .uk
>> http://greyskin.co.uk
>>
>>
>> "Zeng" wrote:
>>
>> >
>> > I finally narrowed down my code to this situation, quite a few (not
>> > all)
> of
>> > my CMyClass objects got hold up after each run of this function via the >> > simple webpage that shows NumberEd editbox. My memory profile shows
> that
>> > those instances survive 3 rounds of GC collections - it's not what I
>> > expected. In my real code, CMyClass occupies big amount of memory and > they
>> > all share one stance of another class that I don't have enough
>> > memory
> hold
>> > more than a just a few in the memory. Notice that the finalizaer the > my
>> > CMyClass makes a big difference in demonstrating this issue, w/o it the >> > problem doesn't exist. The interesting thing is if I run the page
> again,
>> > the old dangling ones got destroyed and the new ones become
>> > dangling.
>> > Am
> I
>> > missing something about the GC? Do I need to explicitly implement
>> > and
> call
>> > dispose for these classes instead of relying on GC to promptly collect > it?
>> > Apparently somehow these objects can survive the automatic
>> > collections...disposing it would help. Thanks for your comment and
>> > help.
>> >
>> > internal class CMyClass
>> > {
>> > ArrayList m_array = new ArrayList( 50000 );
>> > private string m_idStr;
>> > private Guid m_guid;
>> > internal CMyClass( int n )
>> > {
>> > for( int i = 0; i < n; ++i )
>> > m_array.Add( Guid.NewGuid() );
>> >
>> > m_guid = Guid.NewGuid();
>> > m_idStr = m_guid.ToString();
>> > }
>> >
>> > internal Guid id
>> > {
>> > get{ return (Guid ) m_array[ 0 ]; }
>> > }
>> >
>> > ~CMyClass()
>> > {
>> > // Trace.Write( m_guid, m_idStr );
>> > }
>> >
>> > }
>> > private void RunBtn_Click(object sender, System.EventArgs e)
>> > {
>> > ResultEd.Text = "";
>> > try
>> > {
>> >
>> > for( int i = 0; i < int.Parse( NumberEd.Text );
>> > ++i )
>> > {
>> >
>> > Hashtable table = new Hashtable( 100 );
>> > ArrayList ids = new ArrayList( 10 );
>> > for( int j = 0; j < 10; ++j )
>> > {
>> > Guid id = Guid.NewGuid();
>> > table[ id ] = null;
>> > ids.Add( id );
>> > }
>> >
>> >
>> > for( int k=0; k < 10; ++k )
>> > {
>> > foreach( Guid id in ids )
>> > {
>> > table[ id ] = new CMyClass( 10 );
>> > }
>> >
>> > CMyClass myobj;
>> > foreach( Guid id in ids )
>> > {
>> > myobj = (CMyClass) table[ id ];
>> > myobj.id.ToString();
>> > }
>> > } // for k
>> > } // for
>> > }
>> > catch( Exception ex )
>> > {
>> > ResultEd.Text = ex.Message + "...CallSTack:" +
>> > ex.StackTrace;
>> > }
>> >
>> > GC.Collect();
>> > GC.WaitForPendingFinalizers();
>> > GC.Collect();
>> >
>> > GC.WaitForPendingFinalizers();
>> > GC.Collect();
>> >
>> > ResultEd.Text = "Done";
>> > }
>> >
>> >
>> >
>> >
>
>



Nov 17 '05 #14

P: n/a
From what I understand, Dispose method doesn't help freeing manage
resources, and that's consistent with what you are saying.

About the hosting process tries to do a full GC run before it recycles based
on MemoryLimit%; I don't believe it at this point, if there is such thing as
full GC and it's doing what we expect, then it should have been exposed so
we - developers - can call it when we need to bring down the heap size
immediately (of course we don't need this if full GC is actually possible
privately to the framework, but I don't believe it). How many times should
I try to call GC.Collect to free the dangling objects in my demo code? And
if GC.Collect doesn't do what "Collect" means, what is its use? Purely
advertising?

Imagine somebody sell you a cabinet and there is knob on it, and he tells
you that yes that's a knob but don't use it, you NEVER need or want to use
it. If you actually never need to use it then it should be only for
decoration :) but that was only a speculation - and one day you decide to
pull or turn it, and it doesn't do anything ... hahaha who is more insane,
the person tries to use the knob or the person put the knob on the cabinet
and didn't think it's for decoration??

"Willy Denoyette [MVP]" <wi*************@telenet.be> wrote in message
news:eA**************@TK2MSFTNGP10.phx.gbl...
Sorry what I meant was ""there is no documentation ... AND they don't apply here". If you need more info on GC safe points I'm afraid you'll have to
look in the source code files of the CLR if you happen to have a Source Code License. Anyway, when your code calls GC.Collect it's always at a safe GC
point, it's only when a GC is "induced" that it might get postponed when
your code is not at a GC safe point.
What Billr proposed makes little sense in your case because your class don't own unmanaged resources, like DB connections, unmanaged memory OS handles
etc..., it only consumes managed heap memory which is taken care of by the
GC, there is no need to force collections by calling GC.Collect yourself.
But if you really think you have to implement IDisposable, go ahead, but
please tell us what you will do in your Dispose method.

I guess I'm more familiar with the process model than you might think. The
asp.net hosting process recycles when it's Working Set exceeds the
memoryLimit% of total available memory, but the hosting process will try to survive first by forcing a full GC run, followed by an attempt to reduce the working set, then and ONLY when it's WS still exceeds the MemoryLimit% it
will recycle, else it simply continues to run.
In case the WS could not be reduced it's simply because an application
hosted in asp.net allocates too much memory or as a result of heap
fragmentation (take care when allocating many large objects (>85Kb)), or as a result of a design error.
When it happens on a production system, it must be considered an application error , because the memoryLimit%, available system memory, number of active clients etc.. should have been defined during staging, when you performed
your load/stress testing and your workload modeling.

Willy.

"Zeng" <Ze******@hotmail.com> wrote in message
news:%2****************@TK2MSFTNGP09.phx.gbl...
I'm not sure on what you mean by "there is no documentation
available...because they don't apply here...". The existance of a
document
doesn't depend on what part of version of my code was posted. I
appreciate
your help looking into this for me, many people would just ignore posts
and
move on even they know the answer or have some comments, but I don't think we are going anywhere with it. My response was to BillR who proposes that I
should be implementing the IDisposable.

It's the production environment, if the process get recycled, all my cache in the memory will have to be reloaded when it goes back up. That would
cause delay to the service that we want to provide. Sounds like you are
not
familiar with the processModel entry with attribute memoryLimit="60" as
default, it's in the machine.config file. thanks!
"Willy Denoyette [MVP]" <wi*************@telenet.be> wrote in message
news:O5*************@TK2MSFTNGP15.phx.gbl...
Again, you don't have to implement IDisposable when you don't deal with
managed resources. What do you expect to do in your Dispose method? And
No
there is no documentation available on Safe points, because they don't

apply
here (at least not in the code snip you've posted).
I'm also not clear on what you mean with recycling the asp.net process,
is
this something you intend to do or is it something that you are
expecting to
be done automatically, anyway before the asp.net process recycles, all
application domains get unloaded, and this implies a GC run and a

finalizer
run, so all objects (still referenced too) will be collected , but even

when
some objects aren't collected, all memory once allocated for the
process will return to the OS when the process ends. So what are you afraid of?
Willy.

"Zeng" <Ze******@hotmail.com> wrote in message
news:uX**************@tk2msftngp13.phx.gbl...
> Relying on IDisposable won't work easily in the multi-threading

scenarios.
> Since the memory required for each object is big, I have put them on
> static
> variable to share it among the servicing threads. Think of CMyClass is > a
> spell-grammar-checker that helps looking up things and provide

suggestions
> for correction for many users create their documents online. In this
> scenario, looks like there is the only choice
> --> Make CMyClass disposable and create managing component (internal or > external to the class) just to coordinate when and which objects are

done
> just to call Dispose. This sounds like the intensive plumbing and
> error-prone approach that I was so used to with C++
>
> Conceptually, this is the drawback of a smart system, the programmer

knows
> what he/she needs to be done but can't change its behavior (which is

very
> very smart most of the time)
>
> By the way, where can I find a documentation about the safe-points?
> Wouldn't that be better that there is a call to wait for the system to be
> done with collection and there is a safe point in that method? And is
> there
> a safe point in the component that checks for memory usage and
recycle the
> aspnet process when 60%(default) is reached?
>
>
>
> "billr" <bi***@discussions.microsoft.com> wrote in message
> news:3B**********************************@microsof t.com...
>> and just to add my two pennies worth ...
>>
>> Although you may call GC.Collect(), much the same as in Java when
you try
> to
>> force the VM to run garbage collection, it will still run at it's
>> earliest
>> convenience.
>>
>> During compilation, your code is injected with "safe points" whereby

the
> GC
>> can hijack the thread and take control to do its work. Now, when you

call
>> GC.Collect() your code might not be in a stable enough state for the
>> GC
>> to
>> run, and the only way that the GC can know that it is safe to run is
>> if
>> it
>> has reached a "safe point".
>>
>> Generally speaking, it is bad practice to call GC.Collect() since
you >> will
>> inadvertantly interrupt a perfectly (or near to) working system, and

you
>> yourself can cause all sorts of naughtiness to occur.
>>
>> My choice of preference (as it is for a lot of developers) is to
>> implement
>> IDisposable.
>>
>> AND, yes, our code should be easily readable and left in a state that >> renders it possible for future devlopers to look at it and see what is > going
>> on (for maintenance reasons, or whatever), however, designing our

classes
>> "off centre" just in case, the next developer doesn't know as much as us
> is a
>> pretty poor choice IMHO.
>>
>> --
>> Of all words of tongue and pen, the saddest are: "It might have
been" >>
>> Bill.Richards @ greyskin .co .uk
>> http://greyskin.co.uk
>>
>>
>> "Zeng" wrote:
>>
>> >
>> > I finally narrowed down my code to this situation, quite a few (not >> > all)
> of
>> > my CMyClass objects got hold up after each run of this function via the
>> > simple webpage that shows NumberEd editbox. My memory profile
shows > that
>> > those instances survive 3 rounds of GC collections - it's not what I >> > expected. In my real code, CMyClass occupies big amount of memory

and
> they
>> > all share one stance of another class that I don't have enough
>> > memory
> hold
>> > more than a just a few in the memory. Notice that the finalizaer

the
> my
>> > CMyClass makes a big difference in demonstrating this issue, w/o it the
>> > problem doesn't exist. The interesting thing is if I run the page
> again,
>> > the old dangling ones got destroyed and the new ones become
>> > dangling.
>> > Am
> I
>> > missing something about the GC? Do I need to explicitly implement
>> > and
> call
>> > dispose for these classes instead of relying on GC to promptly

collect
> it?
>> > Apparently somehow these objects can survive the automatic
>> > collections...disposing it would help. Thanks for your comment and
>> > help.
>> >
>> > internal class CMyClass
>> > {
>> > ArrayList m_array = new ArrayList( 50000 );
>> > private string m_idStr;
>> > private Guid m_guid;
>> > internal CMyClass( int n )
>> > {
>> > for( int i = 0; i < n; ++i )
>> > m_array.Add( Guid.NewGuid() );
>> >
>> > m_guid = Guid.NewGuid();
>> > m_idStr = m_guid.ToString();
>> > }
>> >
>> > internal Guid id
>> > {
>> > get{ return (Guid ) m_array[ 0 ]; }
>> > }
>> >
>> > ~CMyClass()
>> > {
>> > // Trace.Write( m_guid, m_idStr );
>> > }
>> >
>> > }
>> > private void RunBtn_Click(object sender, System.EventArgs

e) >> > {
>> > ResultEd.Text = "";
>> > try
>> > {
>> >
>> > for( int i = 0; i < int.Parse( NumberEd.Text );
>> > ++i )
>> > {
>> >
>> > Hashtable table = new Hashtable( 100 );
>> > ArrayList ids = new ArrayList( 10 );
>> > for( int j = 0; j < 10; ++j )
>> > {
>> > Guid id = Guid.NewGuid();
>> > table[ id ] = null;
>> > ids.Add( id );
>> > }
>> >
>> >
>> > for( int k=0; k < 10; ++k )
>> > {
>> > foreach( Guid id in ids )
>> > {
>> > table[ id ] = new CMyClass( 10 );
>> > }
>> >
>> > CMyClass myobj;
>> > foreach( Guid id in ids )
>> > {
>> > myobj = (CMyClass) table[ id ];
>> > myobj.id.ToString();
>> > }
>> > } // for k
>> > } // for
>> > }
>> > catch( Exception ex )
>> > {
>> > ResultEd.Text = ex.Message + "...CallSTack:" +
>> > ex.StackTrace;
>> > }
>> >
>> > GC.Collect();
>> > GC.WaitForPendingFinalizers();
>> > GC.Collect();
>> >
>> > GC.WaitForPendingFinalizers();
>> > GC.Collect();
>> >
>> > ResultEd.Text = "Done";
>> > }
>> >
>> >
>> >
>> >
>
>



Nov 17 '05 #15

P: n/a
I guess it's time for me to make my apologies. The point of my mentioning
Safe Points was to illustrate the workings of the GC.

Safe Points are points in the code that have been identified as it being
safe for the GC to suspend ALL threads in order to do its thing.

A problem faced by the GC is that when compacting the heap it must make sure
that it does not change the structure of the object graphs (internal
tree-like structures used for determining reachable/non-reachable objects
i.e. referenced/non-referenced objects), nor should it change the structure
of the heap. In order to achieve this, the GC is responsible for maintaining
object references (i.e. adjusting references within objects contained within
the graphs), because of course, when an object is moved in the heap, any
existing references to that object will be invalid. The only safe way to cope
with this is to suspend all application threads during garbage collection. It
is for this reason that the JIT compiler inserts Safe Points into the code,
i.e. points in the execution path that are safe for thread suspension.

Garbage collection occurs by the GC effectively "hijacking" the thread by
inserting a different return address from the safe point. When GC is
complete, .NET sends the thread back to its original return address and
normal execution continues.

Garbage collection is triggered in .NET either by application shutdown, heap
exhaustion, or an explicit call GC.Collect(). With the exception of
application shutdown, however, garbage collection only occurs when the
execution path reaches a safe point.

IMPORTANT NOTE :
================

When the GC has determined that an object is in fact garbage, the first
thing it does is check the object's metadata, and if the object implements
Finalize(), instead of destroying the object, it is marked as reachable
(which is not what you want if you want your object to be destroyed
immediately) and is moved from its original graph to another graph called the
"finalized queue". A seperate thread then iterates over the finalized queue
invoking Finalize() on all objects contained therein; then -and only then-
are the objects removed from the queue and destroyed, hence freeing up its
heap space.

So, essentially, when you implement Finalize() you are telling the GC that
when the object is no longer referenced it is NOT SAFE for deletion YET, and
Finalize() must first be invoked, which means that the object is not
destroyed for approximately two runs of garbage collection. It is for this
reason that deterministic finalization is recommended.

EXPLICIT garbage collection is not recommended becuase it is an expensive
operation involving scanning object graphs, thread suspension and resumption,
thread context switches, and EXTENSIVE use of reflection to read the objects'
metadata.

I hope that that clears up the confusion I might have injected into the
discussion, also, I hope it clears up why you should not declare a finalizer,
even if there is no body. The simple act of declaring a finalizer ensures
that the object lives for longer than you might actually intend/require.

--
Of all words of tongue and pen, the saddest are: "It might have been"

Bill.Richards @ greyskin .co .uk
http://greyskin.co.uk
"Zeng" wrote:
I'm not sure on what you mean by "there is no documentation
available...because they don't apply here...". The existance of a document
doesn't depend on what part of version of my code was posted. I appreciate
your help looking into this for me, many people would just ignore posts and
move on even they know the answer or have some comments, but I don't think
we are going anywhere with it. My response was to BillR who proposes that I
should be implementing the IDisposable.

It's the production environment, if the process get recycled, all my cache
in the memory will have to be reloaded when it goes back up. That would
cause delay to the service that we want to provide. Sounds like you are not
familiar with the processModel entry with attribute memoryLimit="60" as
default, it's in the machine.config file. thanks!
"Willy Denoyette [MVP]" <wi*************@telenet.be> wrote in message
news:O5*************@TK2MSFTNGP15.phx.gbl...
Again, you don't have to implement IDisposable when you don't deal with
managed resources. What do you expect to do in your Dispose method? And No
there is no documentation available on Safe points, because they don't

apply
here (at least not in the code snip you've posted).
I'm also not clear on what you mean with recycling the asp.net process,

is
this something you intend to do or is it something that you are expecting

to
be done automatically, anyway before the asp.net process recycles, all
application domains get unloaded, and this implies a GC run and a

finalizer
run, so all objects (still referenced too) will be collected , but even

when
some objects aren't collected, all memory once allocated for the process
will return to the OS when the process ends. So what are you afraid of?
Willy.

"Zeng" <Ze******@hotmail.com> wrote in message
news:uX**************@tk2msftngp13.phx.gbl...
Relying on IDisposable won't work easily in the multi-threading scenarios. Since the memory required for each object is big, I have put them on
static
variable to share it among the servicing threads. Think of CMyClass is a
spell-grammar-checker that helps looking up things and provide suggestions for correction for many users create their documents online. In this
scenario, looks like there is the only choice
--> Make CMyClass disposable and create managing component (internal or
external to the class) just to coordinate when and which objects are done just to call Dispose. This sounds like the intensive plumbing and
error-prone approach that I was so used to with C++

Conceptually, this is the drawback of a smart system, the programmer knows what he/she needs to be done but can't change its behavior (which is very very smart most of the time)

By the way, where can I find a documentation about the safe-points?
Wouldn't that be better that there is a call to wait for the system to be done with collection and there is a safe point in that method? And is
there
a safe point in the component that checks for memory usage and recycle the aspnet process when 60%(default) is reached?

"billr" <bi***@discussions.microsoft.com> wrote in message
news:3B**********************************@microsof t.com...
> and just to add my two pennies worth ...
>
> Although you may call GC.Collect(), much the same as in Java when you try to
> force the VM to run garbage collection, it will still run at it's
> earliest
> convenience.
>
> During compilation, your code is injected with "safe points" whereby the GC
> can hijack the thread and take control to do its work. Now, when you call> GC.Collect() your code might not be in a stable enough state for the GC
> to
> run, and the only way that the GC can know that it is safe to run is if
> it
> has reached a "safe point".
>
> Generally speaking, it is bad practice to call GC.Collect() since you
> will
> inadvertantly interrupt a perfectly (or near to) working system, and you> yourself can cause all sorts of naughtiness to occur.
>
> My choice of preference (as it is for a lot of developers) is to
> implement
> IDisposable.
>
> AND, yes, our code should be easily readable and left in a state that
> renders it possible for future devlopers to look at it and see what is
going
> on (for maintenance reasons, or whatever), however, designing our classes> "off centre" just in case, the next developer doesn't know as much as us is a
> pretty poor choice IMHO.
>
> --
> Of all words of tongue and pen, the saddest are: "It might have been"
>
> Bill.Richards @ greyskin .co .uk
> http://greyskin.co.uk
>
>
> "Zeng" wrote:
>
> >
> > I finally narrowed down my code to this situation, quite a few (not
> > all)
of
> > my CMyClass objects got hold up after each run of this function via the> > simple webpage that shows NumberEd editbox. My memory profile shows
that
> > those instances survive 3 rounds of GC collections - it's not what I
> > expected. In my real code, CMyClass occupies big amount of memory and they
> > all share one stance of another class that I don't have enough memory
hold
> > more than a just a few in the memory. Notice that the finalizaer the my
> > CMyClass makes a big difference in demonstrating this issue, w/o it the> > problem doesn't exist. The interesting thing is if I run the page
again,
> > the old dangling ones got destroyed and the new ones become dangling.
> > Am
I
> > missing something about the GC? Do I need to explicitly implement and
call
> > dispose for these classes instead of relying on GC to promptly collect it?
> > Apparently somehow these objects can survive the automatic
> > collections...disposing it would help. Thanks for your comment and
> > help.
> >
> > internal class CMyClass
> > {
> > ArrayList m_array = new ArrayList( 50000 );
> > private string m_idStr;
> > private Guid m_guid;
> > internal CMyClass( int n )
> > {
> > for( int i = 0; i < n; ++i )
> > m_array.Add( Guid.NewGuid() );
> >
> > m_guid = Guid.NewGuid();
> > m_idStr = m_guid.ToString();
> > }
> >
> > internal Guid id
> > {
> > get{ return (Guid ) m_array[ 0 ]; }
> > }
> >
> > ~CMyClass()
> > {
> > // Trace.Write( m_guid, m_idStr );
> > }
> >
> > }
> > private void RunBtn_Click(object sender, System.EventArgs e)
> > {
> > ResultEd.Text = "";
> > try
> > {
> >
> > for( int i = 0; i < int.Parse( NumberEd.Text ); ++i )
> > {
> >
> > Hashtable table = new Hashtable( 100 );
> > ArrayList ids = new ArrayList( 10 );
> > for( int j = 0; j < 10; ++j )
> > {
> > Guid id = Guid.NewGuid();
> > table[ id ] = null;
> > ids.Add( id );
> > }
> >
> >
> > for( int k=0; k < 10; ++k )
> > {
> > foreach( Guid id in ids )
> > {
> > table[ id ] = new CMyClass( 10 );
> > }
> >
> > CMyClass myobj;
> > foreach( Guid id in ids )
> > {
> > myobj = (CMyClass) table[ id ];
> > myobj.id.ToString();
> > }
> > } // for k
> > } // for
> > }
> > catch( Exception ex )
> > {
> > ResultEd.Text = ex.Message + "...CallSTack:" +
> > ex.StackTrace;
> > }
> >
> > GC.Collect();
> > GC.WaitForPendingFinalizers();
> > GC.Collect();
> >
> > GC.WaitForPendingFinalizers();
> > GC.Collect();
> >
> > ResultEd.Text = "Done";
> > }
> >
> >
> >
> >



Nov 17 '05 #16

P: n/a
GC.Collect() does do what it says on the packet, i.e. it does cause the GC to
run; however, it will only run at its next convenient opportunity -which
might or might not be the next time it was going to run anyway.

You can use GC.Collect(), and I didn't mean to imply that you cannot,
however, it should be considered that this does entail additional overhead,
and garbage collection will not necessarily run as soon as you have made the
call.

I completely agree with your analogy, however, I think that it does not
really apply here, and maybe my original post should have been a little
clearer on this point.

The method is supplied so that you can call it, but under normal operating
conditions, you really shouldn't NEED to make the call.

--
Of all words of tongue and pen, the saddest are: "It might have been"

Bill.Richards @ greyskin .co .uk
http://greyskin.co.uk
"Zeng" wrote:
From what I understand, Dispose method doesn't help freeing manage
resources, and that's consistent with what you are saying.

About the hosting process tries to do a full GC run before it recycles based
on MemoryLimit%; I don't believe it at this point, if there is such thing as
full GC and it's doing what we expect, then it should have been exposed so
we - developers - can call it when we need to bring down the heap size
immediately (of course we don't need this if full GC is actually possible
privately to the framework, but I don't believe it). How many times should
I try to call GC.Collect to free the dangling objects in my demo code? And
if GC.Collect doesn't do what "Collect" means, what is its use? Purely
advertising?

Imagine somebody sell you a cabinet and there is knob on it, and he tells
you that yes that's a knob but don't use it, you NEVER need or want to use
it. If you actually never need to use it then it should be only for
decoration :) but that was only a speculation - and one day you decide to
pull or turn it, and it doesn't do anything ... hahaha who is more insane,
the person tries to use the knob or the person put the knob on the cabinet
and didn't think it's for decoration??

"Willy Denoyette [MVP]" <wi*************@telenet.be> wrote in message
news:eA**************@TK2MSFTNGP10.phx.gbl...
Sorry what I meant was ""there is no documentation ... AND they don't

apply
here". If you need more info on GC safe points I'm afraid you'll have to
look in the source code files of the CLR if you happen to have a Source

Code
License. Anyway, when your code calls GC.Collect it's always at a safe GC
point, it's only when a GC is "induced" that it might get postponed when
your code is not at a GC safe point.
What Billr proposed makes little sense in your case because your class

don't
own unmanaged resources, like DB connections, unmanaged memory OS handles
etc..., it only consumes managed heap memory which is taken care of by the
GC, there is no need to force collections by calling GC.Collect yourself.
But if you really think you have to implement IDisposable, go ahead, but
please tell us what you will do in your Dispose method.

I guess I'm more familiar with the process model than you might think. The
asp.net hosting process recycles when it's Working Set exceeds the
memoryLimit% of total available memory, but the hosting process will try

to
survive first by forcing a full GC run, followed by an attempt to reduce

the
working set, then and ONLY when it's WS still exceeds the MemoryLimit% it
will recycle, else it simply continues to run.
In case the WS could not be reduced it's simply because an application
hosted in asp.net allocates too much memory or as a result of heap
fragmentation (take care when allocating many large objects (>85Kb)), or

as
a result of a design error.
When it happens on a production system, it must be considered an

application
error , because the memoryLimit%, available system memory, number of

active
clients etc.. should have been defined during staging, when you performed
your load/stress testing and your workload modeling.

Willy.

"Zeng" <Ze******@hotmail.com> wrote in message
news:%2****************@TK2MSFTNGP09.phx.gbl...
I'm not sure on what you mean by "there is no documentation
available...because they don't apply here...". The existance of a
document
doesn't depend on what part of version of my code was posted. I
appreciate
your help looking into this for me, many people would just ignore posts
and
move on even they know the answer or have some comments, but I don't think we are going anywhere with it. My response was to BillR who proposes that I
should be implementing the IDisposable.

It's the production environment, if the process get recycled, all my cache in the memory will have to be reloaded when it goes back up. That would
cause delay to the service that we want to provide. Sounds like you are
not
familiar with the processModel entry with attribute memoryLimit="60" as
default, it's in the machine.config file. thanks!
"Willy Denoyette [MVP]" <wi*************@telenet.be> wrote in message
news:O5*************@TK2MSFTNGP15.phx.gbl...
> Again, you don't have to implement IDisposable when you don't deal with
> managed resources. What do you expect to do in your Dispose method? And
> No
> there is no documentation available on Safe points, because they don't
apply
> here (at least not in the code snip you've posted).
> I'm also not clear on what you mean with recycling the asp.net process, is
> this something you intend to do or is it something that you are expecting to
> be done automatically, anyway before the asp.net process recycles, all
> application domains get unloaded, and this implies a GC run and a
finalizer
> run, so all objects (still referenced too) will be collected , but even
when
> some objects aren't collected, all memory once allocated for the process> will return to the OS when the process ends. So what are you afraid of?
>
>
> Willy.
>
> "Zeng" <Ze******@hotmail.com> wrote in message
> news:uX**************@tk2msftngp13.phx.gbl...
> > Relying on IDisposable won't work easily in the multi-threading
scenarios.
> > Since the memory required for each object is big, I have put them on
> > static
> > variable to share it among the servicing threads. Think of CMyClass is> > a
> > spell-grammar-checker that helps looking up things and provide
suggestions
> > for correction for many users create their documents online. In this
> > scenario, looks like there is the only choice
> > --> Make CMyClass disposable and create managing component (internal or> > external to the class) just to coordinate when and which objects are
done
> > just to call Dispose. This sounds like the intensive plumbing and
> > error-prone approach that I was so used to with C++
> >
> > Conceptually, this is the drawback of a smart system, the programmer
knows
> > what he/she needs to be done but can't change its behavior (which is
very
> > very smart most of the time)
> >
> > By the way, where can I find a documentation about the safe-points?
> > Wouldn't that be better that there is a call to wait for the system to be
> > done with collection and there is a safe point in that method? And is
> > there
> > a safe point in the component that checks for memory usage and recycle the
> > aspnet process when 60%(default) is reached?
> >
> >
> >
> > "billr" <bi***@discussions.microsoft.com> wrote in message
> > news:3B**********************************@microsof t.com...
> >> and just to add my two pennies worth ...
> >>
> >> Although you may call GC.Collect(), much the same as in Java when you try
> > to
> >> force the VM to run garbage collection, it will still run at it's
> >> earliest
> >> convenience.
> >>
> >> During compilation, your code is injected with "safe points" whereby
the
> > GC
> >> can hijack the thread and take control to do its work. Now, when you
call
> >> GC.Collect() your code might not be in a stable enough state for the
> >> GC
> >> to
> >> run, and the only way that the GC can know that it is safe to run is
> >> if
> >> it
> >> has reached a "safe point".
> >>
> >> Generally speaking, it is bad practice to call GC.Collect() since you> >> will
> >> inadvertantly interrupt a perfectly (or near to) working system, and
you
> >> yourself can cause all sorts of naughtiness to occur.
> >>
> >> My choice of preference (as it is for a lot of developers) is to
> >> implement
> >> IDisposable.
> >>
> >> AND, yes, our code should be easily readable and left in a state that> >> renders it possible for future devlopers to look at it and see what is> > going
> >> on (for maintenance reasons, or whatever), however, designing our
classes
> >> "off centre" just in case, the next developer doesn't know as much as us
> > is a
> >> pretty poor choice IMHO.
> >>
> >> --
> >> Of all words of tongue and pen, the saddest are: "It might have been"> >>
> >> Bill.Richards @ greyskin .co .uk
> >> http://greyskin.co.uk
> >>
> >>
> >> "Zeng" wrote:
> >>
> >> >
> >> > I finally narrowed down my code to this situation, quite a few (not> >> > all)
> > of
> >> > my CMyClass objects got hold up after each run of this function via the
> >> > simple webpage that shows NumberEd editbox. My memory profile shows> > that
> >> > those instances survive 3 rounds of GC collections - it's not what I> >> > expected. In my real code, CMyClass occupies big amount of memory
and
> > they
> >> > all share one stance of another class that I don't have enough
> >> > memory
> > hold
> >> > more than a just a few in the memory. Notice that the finalizaer
the
> > my
> >> > CMyClass makes a big difference in demonstrating this issue, w/o it the
> >> > problem doesn't exist. The interesting thing is if I run the page
> > again,
> >> > the old dangling ones got destroyed and the new ones become
> >> > dangling.
> >> > Am
> > I
> >> > missing something about the GC? Do I need to explicitly implement
> >> > and
> > call
> >> > dispose for these classes instead of relying on GC to promptly
collect
> > it?
> >> > Apparently somehow these objects can survive the automatic
> >> > collections...disposing it would help. Thanks for your comment and
> >> > help.
> >> >
> >> > internal class CMyClass
> >> > {
> >> > ArrayList m_array = new ArrayList( 50000 );
> >> > private string m_idStr;
> >> > private Guid m_guid;
> >> > internal CMyClass( int n )
> >> > {
> >> > for( int i = 0; i < n; ++i )
> >> > m_array.Add( Guid.NewGuid() );
> >> >
> >> > m_guid = Guid.NewGuid();
> >> > m_idStr = m_guid.ToString();
> >> > }
> >> >
> >> > internal Guid id
> >> > {
> >> > get{ return (Guid ) m_array[ 0 ]; }
> >> > }
> >> >
> >> > ~CMyClass()
> >> > {
> >> > // Trace.Write( m_guid, m_idStr );
> >> > }
> >> >
> >> > }
> >> > private void RunBtn_Click(object sender, System.EventArgs e)> >> > {
> >> > ResultEd.Text = "";
> >> > try
> >> > {
> >> >
> >> > for( int i = 0; i < int.Parse( NumberEd.Text );
> >> > ++i )
> >> > {
> >> >
> >> > Hashtable table = new Hashtable( 100 );
> >> > ArrayList ids = new ArrayList( 10 );
> >> > for( int j = 0; j < 10; ++j )
> >> > {
> >> > Guid id = Guid.NewGuid();
> >> > table[ id ] = null;
> >> > ids.Add( id );
> >> > }
> >> >
> >> >
> >> > for( int k=0; k < 10; ++k )

Nov 17 '05 #17

P: n/a
Seems like you have a fundamental mis-understanding on what the GC is meant
for and how it's actually performing.
The GC's task is, to collect the memory space occupied by non-reachable
objects and compact the generation it is actually collecting, so that a
contiguous free space remains in the heap to add new objects.
A full GC is a GC run that collects all generations, the current version of
the CLR has 3 generational logical heaps plus a separate large object heap
(LOH), from code you can ask for a GC run by calling GC.Collect(n) where n
indicates the generation to end with, a collection always starts with
generation 0.
GC.Collect() collects all generations plus the LOH, that's why it's called a
full collect.

However, it's NOT the task of the GC to bring down the heap size, that's the
task of the CLR memory manager , or the hosting process memory manager (if
any) in close cooperation with the OS.

Your code sample needs at least two GC.Collect() calls, that's because you
have a Finalizer (destructor in C# parlance).
When an instance of a finalizable object gets instantiated, it's registered
as finalizable.
When it is no longer rooted at the next GC run, it will be moved to the
finalizable queue, where it stays until after the finalizer has run, after
which it's removed from the finalizer queue and it becomes eligible for
collection.
Note that it's possible that not all finalizables are immediately finalized,
all depends on the load of the system and the time the finalizer thread
spends finalizing objects. The finalizer thread can be suspended before all
finalizer have run, that's why we say at LEAST 2 GC runs, and why we suggest
against destructors in C#.

Willy.

PS I suggest you start reading these (somewhat outdated) articles , before
you start arguing about a subject you don't seem to fully understand.
http://msdn.microsoft.com/msdnmag/is...I/default.aspx
http://msdn.microsoft.com/msdnmag/is...2/default.aspx

"Zeng" <Ze******@hotmail.com> wrote in message
news:eq**************@TK2MSFTNGP14.phx.gbl...
From what I understand, Dispose method doesn't help freeing manage
resources, and that's consistent with what you are saying.

About the hosting process tries to do a full GC run before it recycles
based
on MemoryLimit%; I don't believe it at this point, if there is such thing
as
full GC and it's doing what we expect, then it should have been exposed so
we - developers - can call it when we need to bring down the heap size
immediately (of course we don't need this if full GC is actually possible
privately to the framework, but I don't believe it). How many times
should
I try to call GC.Collect to free the dangling objects in my demo code?
And
if GC.Collect doesn't do what "Collect" means, what is its use? Purely
advertising?

Imagine somebody sell you a cabinet and there is knob on it, and he tells
you that yes that's a knob but don't use it, you NEVER need or want to use
it. If you actually never need to use it then it should be only for
decoration :) but that was only a speculation - and one day you decide to
pull or turn it, and it doesn't do anything ... hahaha who is more insane,
the person tries to use the knob or the person put the knob on the cabinet
and didn't think it's for decoration??

"Willy Denoyette [MVP]" <wi*************@telenet.be> wrote in message
news:eA**************@TK2MSFTNGP10.phx.gbl...
Sorry what I meant was ""there is no documentation ... AND they don't

apply
here". If you need more info on GC safe points I'm afraid you'll have to
look in the source code files of the CLR if you happen to have a Source

Code
License. Anyway, when your code calls GC.Collect it's always at a safe GC
point, it's only when a GC is "induced" that it might get postponed when
your code is not at a GC safe point.
What Billr proposed makes little sense in your case because your class

don't
own unmanaged resources, like DB connections, unmanaged memory OS handles
etc..., it only consumes managed heap memory which is taken care of by
the
GC, there is no need to force collections by calling GC.Collect yourself.
But if you really think you have to implement IDisposable, go ahead, but
please tell us what you will do in your Dispose method.

I guess I'm more familiar with the process model than you might think.
The
asp.net hosting process recycles when it's Working Set exceeds the
memoryLimit% of total available memory, but the hosting process will try

to
survive first by forcing a full GC run, followed by an attempt to reduce

the
working set, then and ONLY when it's WS still exceeds the MemoryLimit% it
will recycle, else it simply continues to run.
In case the WS could not be reduced it's simply because an application
hosted in asp.net allocates too much memory or as a result of heap
fragmentation (take care when allocating many large objects (>85Kb)), or

as
a result of a design error.
When it happens on a production system, it must be considered an

application
error , because the memoryLimit%, available system memory, number of

active
clients etc.. should have been defined during staging, when you performed
your load/stress testing and your workload modeling.

Willy.

"Zeng" <Ze******@hotmail.com> wrote in message
news:%2****************@TK2MSFTNGP09.phx.gbl...
> I'm not sure on what you mean by "there is no documentation
> available...because they don't apply here...". The existance of a
> document
> doesn't depend on what part of version of my code was posted. I
> appreciate
> your help looking into this for me, many people would just ignore posts
> and
> move on even they know the answer or have some comments, but I don't think > we are going anywhere with it. My response was to BillR who proposes that > I
> should be implementing the IDisposable.
>
> It's the production environment, if the process get recycled, all my cache > in the memory will have to be reloaded when it goes back up. That
> would
> cause delay to the service that we want to provide. Sounds like you
> are
> not
> familiar with the processModel entry with attribute memoryLimit="60" as
> default, it's in the machine.config file. thanks!
>
>
> "Willy Denoyette [MVP]" <wi*************@telenet.be> wrote in message
> news:O5*************@TK2MSFTNGP15.phx.gbl...
>> Again, you don't have to implement IDisposable when you don't deal
>> with
>> managed resources. What do you expect to do in your Dispose method?
>> And
>> No
>> there is no documentation available on Safe points, because they don't
> apply
>> here (at least not in the code snip you've posted).
>> I'm also not clear on what you mean with recycling the asp.net process, > is
>> this something you intend to do or is it something that you are expecting > to
>> be done automatically, anyway before the asp.net process recycles,
>> all
>> application domains get unloaded, and this implies a GC run and a
> finalizer
>> run, so all objects (still referenced too) will be collected , but
>> even
> when
>> some objects aren't collected, all memory once allocated for the process >> will return to the OS when the process ends. So what are you afraid
>> of?
>>
>>
>> Willy.
>>
>> "Zeng" <Ze******@hotmail.com> wrote in message
>> news:uX**************@tk2msftngp13.phx.gbl...
>> > Relying on IDisposable won't work easily in the multi-threading
> scenarios.
>> > Since the memory required for each object is big, I have put them on
>> > static
>> > variable to share it among the servicing threads. Think of CMyClass is >> > a
>> > spell-grammar-checker that helps looking up things and provide
> suggestions
>> > for correction for many users create their documents online. In
>> > this
>> > scenario, looks like there is the only choice
>> > --> Make CMyClass disposable and create managing component (internal or >> > external to the class) just to coordinate when and which objects are
> done
>> > just to call Dispose. This sounds like the intensive plumbing and
>> > error-prone approach that I was so used to with C++
>> >
>> > Conceptually, this is the drawback of a smart system, the programmer
> knows
>> > what he/she needs to be done but can't change its behavior (which is
> very
>> > very smart most of the time)
>> >
>> > By the way, where can I find a documentation about the safe-points?
>> > Wouldn't that be better that there is a call to wait for the system to > be
>> > done with collection and there is a safe point in that method? And
>> > is
>> > there
>> > a safe point in the component that checks for memory usage and recycle > the
>> > aspnet process when 60%(default) is reached?
>> >
>> >
>> >
>> > "billr" <bi***@discussions.microsoft.com> wrote in message
>> > news:3B**********************************@microsof t.com...
>> >> and just to add my two pennies worth ...
>> >>
>> >> Although you may call GC.Collect(), much the same as in Java when you > try
>> > to
>> >> force the VM to run garbage collection, it will still run at it's
>> >> earliest
>> >> convenience.
>> >>
>> >> During compilation, your code is injected with "safe points"
>> >> whereby
> the
>> > GC
>> >> can hijack the thread and take control to do its work. Now, when
>> >> you
> call
>> >> GC.Collect() your code might not be in a stable enough state for
>> >> the
>> >> GC
>> >> to
>> >> run, and the only way that the GC can know that it is safe to run
>> >> is
>> >> if
>> >> it
>> >> has reached a "safe point".
>> >>
>> >> Generally speaking, it is bad practice to call GC.Collect() since you >> >> will
>> >> inadvertantly interrupt a perfectly (or near to) working system,
>> >> and
> you
>> >> yourself can cause all sorts of naughtiness to occur.
>> >>
>> >> My choice of preference (as it is for a lot of developers) is to
>> >> implement
>> >> IDisposable.
>> >>
>> >> AND, yes, our code should be easily readable and left in a state that >> >> renders it possible for future devlopers to look at it and see what is >> > going
>> >> on (for maintenance reasons, or whatever), however, designing our
> classes
>> >> "off centre" just in case, the next developer doesn't know as much as > us
>> > is a
>> >> pretty poor choice IMHO.
>> >>
>> >> --
>> >> Of all words of tongue and pen, the saddest are: "It might have been" >> >>
>> >> Bill.Richards @ greyskin .co .uk
>> >> http://greyskin.co.uk
>> >>
>> >>
>> >> "Zeng" wrote:
>> >>
>> >> >
>> >> > I finally narrowed down my code to this situation, quite a few (not >> >> > all)
>> > of
>> >> > my CMyClass objects got hold up after each run of this function via > the
>> >> > simple webpage that shows NumberEd editbox. My memory profile shows >> > that
>> >> > those instances survive 3 rounds of GC collections - it's not
>> >> > what I >> >> > expected. In my real code, CMyClass occupies big amount of
>> >> > memory
> and
>> > they
>> >> > all share one stance of another class that I don't have enough
>> >> > memory
>> > hold
>> >> > more than a just a few in the memory. Notice that the
>> >> > finalizaer
> the
>> > my
>> >> > CMyClass makes a big difference in demonstrating this issue, w/o it > the
>> >> > problem doesn't exist. The interesting thing is if I run the
>> >> > page
>> > again,
>> >> > the old dangling ones got destroyed and the new ones become
>> >> > dangling.
>> >> > Am
>> > I
>> >> > missing something about the GC? Do I need to explicitly implement
>> >> > and
>> > call
>> >> > dispose for these classes instead of relying on GC to promptly
> collect
>> > it?
>> >> > Apparently somehow these objects can survive the automatic
>> >> > collections...disposing it would help. Thanks for your comment
>> >> > and
>> >> > help.
>> >> >
>> >> > internal class CMyClass
>> >> > {
>> >> > ArrayList m_array = new ArrayList( 50000 );
>> >> > private string m_idStr;
>> >> > private Guid m_guid;
>> >> > internal CMyClass( int n )
>> >> > {
>> >> > for( int i = 0; i < n; ++i )
>> >> > m_array.Add( Guid.NewGuid() );
>> >> >
>> >> > m_guid = Guid.NewGuid();
>> >> > m_idStr = m_guid.ToString();
>> >> > }
>> >> >
>> >> > internal Guid id
>> >> > {
>> >> > get{ return (Guid ) m_array[ 0 ]; }
>> >> > }
>> >> >
>> >> > ~CMyClass()
>> >> > {
>> >> > // Trace.Write( m_guid, m_idStr );
>> >> > }
>> >> >
>> >> > }
>> >> > private void RunBtn_Click(object sender, System.EventArgs e) >> >> > {
>> >> > ResultEd.Text = "";
>> >> > try
>> >> > {
>> >> >
>> >> > for( int i = 0; i < int.Parse( NumberEd.Text );
>> >> > ++i )
>> >> > {
>> >> >
>> >> > Hashtable table = new Hashtable( 100 );
>> >> > ArrayList ids = new ArrayList( 10 );
>> >> > for( int j = 0; j < 10; ++j )
>> >> > {
>> >> > Guid id = Guid.NewGuid();
>> >> > table[ id ] = null;
>> >> > ids.Add( id );
>> >> > }
>> >> >
>> >> >
>> >> > for( int k=0; k < 10; ++k )
>> >> > {
>> >> > foreach( Guid id in ids )
>> >> > {
>> >> > table[ id ] = new CMyClass( 10 );
>> >> > }
>> >> >
>> >> > CMyClass myobj;
>> >> > foreach( Guid id in ids )
>> >> > {
>> >> > myobj = (CMyClass) table[ id ];
>> >> > myobj.id.ToString();
>> >> > }
>> >> > } // for k
>> >> > } // for
>> >> > }
>> >> > catch( Exception ex )
>> >> > {
>> >> > ResultEd.Text = ex.Message + "...CallSTack:" +
>> >> > ex.StackTrace;
>> >> > }
>> >> >
>> >> > GC.Collect();
>> >> > GC.WaitForPendingFinalizers();
>> >> > GC.Collect();
>> >> >
>> >> > GC.WaitForPendingFinalizers();
>> >> > GC.Collect();
>> >> >
>> >> > ResultEd.Text = "Done";
>> >> > }
>> >> >
>> >> >
>> >> >
>> >> >
>> >
>> >
>>
>>
>
>



Nov 17 '05 #18

P: n/a

"billr" <bi***@discussions.microsoft.com> wrote in message
news:DA**********************************@microsof t.com...

Garbage collection is triggered in .NET either by application shutdown,
heap
exhaustion, or an explicit call GC.Collect(). With the exception of
application shutdown, however, garbage collection only occurs when the
execution path reaches a safe point.


To be precise a GC run can be "induced" by the CLR when the gen0 has reached
a certain threshold, not when the heap is exhausted. This gen0 threshold
starts with a fixed value depending on a number of system (the size of the
Level2 cache, GC flavor, etc...), but is dynamically adjusted during
run-time using GC statistics (allocation pattern and frequency).
Also the GC is 'induced' when all threads are at a safe point to be
suspended, unsafe points are 'signaled' by the JIT, but also by the EE
itself. A flag is set when it's not safe to collect and the EE checks this
flag before it suspends the threads and starts a GC sweep using one of the
suspended threads. Note however that unsafe points are rare, so most of the
time a GC can be initiated.

Willy.

Nov 17 '05 #19

P: n/a
Thanks for that little extra info Willy.
--
Of all words of tongue and pen, the saddest are: "It might have been"

Bill.Richards @ greyskin .co .uk
http://greyskin.co.uk
"Willy Denoyette [MVP]" wrote:

"billr" <bi***@discussions.microsoft.com> wrote in message
news:DA**********************************@microsof t.com...

Garbage collection is triggered in .NET either by application shutdown,
heap
exhaustion, or an explicit call GC.Collect(). With the exception of
application shutdown, however, garbage collection only occurs when the
execution path reaches a safe point.


To be precise a GC run can be "induced" by the CLR when the gen0 has reached
a certain threshold, not when the heap is exhausted. This gen0 threshold
starts with a fixed value depending on a number of system (the size of the
Level2 cache, GC flavor, etc...), but is dynamically adjusted during
run-time using GC statistics (allocation pattern and frequency).
Also the GC is 'induced' when all threads are at a safe point to be
suspended, unsafe points are 'signaled' by the JIT, but also by the EE
itself. A flag is set when it's not safe to collect and the EE checks this
flag before it suspends the threads and starts a GC sweep using one of the
suspended threads. Note however that unsafe points are rare, so most of the
time a GC can be initiated.

Willy.


Nov 17 '05 #20

P: n/a
From this paragraph:
Garbage collection is triggered in .NET either by application shutdown, heap exhaustion, or an explicit call GC.Collect(). With the exception of
application shutdown, however, garbage collection only occurs when the
execution path reaches a safe point.
Does that mean it's possible for my process to get recycled for reach memory
max% even though most of the memory counted as used is no longer needed by
my app and it is not freed because GC hasn't gotten a chance to do so
safely? If that's true, sounds to me that having a finalizer in my class or
not would only *reduce* the chance of that occuring, but not eliminating, is
that accessment accurate to you?

"billr" <bi***@discussions.microsoft.com> wrote in message
news:DA**********************************@microsof t.com... I guess it's time for me to make my apologies. The point of my mentioning
Safe Points was to illustrate the workings of the GC.

Safe Points are points in the code that have been identified as it being
safe for the GC to suspend ALL threads in order to do its thing.

A problem faced by the GC is that when compacting the heap it must make sure that it does not change the structure of the object graphs (internal
tree-like structures used for determining reachable/non-reachable objects
i.e. referenced/non-referenced objects), nor should it change the structure of the heap. In order to achieve this, the GC is responsible for maintaining object references (i.e. adjusting references within objects contained within the graphs), because of course, when an object is moved in the heap, any
existing references to that object will be invalid. The only safe way to cope with this is to suspend all application threads during garbage collection. It is for this reason that the JIT compiler inserts Safe Points into the code, i.e. points in the execution path that are safe for thread suspension.

Garbage collection occurs by the GC effectively "hijacking" the thread by
inserting a different return address from the safe point. When GC is
complete, .NET sends the thread back to its original return address and
normal execution continues.

Garbage collection is triggered in .NET either by application shutdown, heap exhaustion, or an explicit call GC.Collect(). With the exception of
application shutdown, however, garbage collection only occurs when the
execution path reaches a safe point.

IMPORTANT NOTE :
================

When the GC has determined that an object is in fact garbage, the first
thing it does is check the object's metadata, and if the object implements
Finalize(), instead of destroying the object, it is marked as reachable
(which is not what you want if you want your object to be destroyed
immediately) and is moved from its original graph to another graph called the "finalized queue". A seperate thread then iterates over the finalized queue invoking Finalize() on all objects contained therein; then -and only then-
are the objects removed from the queue and destroyed, hence freeing up its
heap space.

So, essentially, when you implement Finalize() you are telling the GC that
when the object is no longer referenced it is NOT SAFE for deletion YET, and Finalize() must first be invoked, which means that the object is not
destroyed for approximately two runs of garbage collection. It is for this
reason that deterministic finalization is recommended.

EXPLICIT garbage collection is not recommended becuase it is an expensive
operation involving scanning object graphs, thread suspension and resumption, thread context switches, and EXTENSIVE use of reflection to read the objects' metadata.

I hope that that clears up the confusion I might have injected into the
discussion, also, I hope it clears up why you should not declare a finalizer, even if there is no body. The simple act of declaring a finalizer ensures
that the object lives for longer than you might actually intend/require.

--
Of all words of tongue and pen, the saddest are: "It might have been"

Bill.Richards @ greyskin .co .uk
http://greyskin.co.uk
"Zeng" wrote:
I'm not sure on what you mean by "there is no documentation
available...because they don't apply here...". The existance of a document doesn't depend on what part of version of my code was posted. I appreciate your help looking into this for me, many people would just ignore posts and move on even they know the answer or have some comments, but I don't think we are going anywhere with it. My response was to BillR who proposes that I should be implementing the IDisposable.

It's the production environment, if the process get recycled, all my cache in the memory will have to be reloaded when it goes back up. That would
cause delay to the service that we want to provide. Sounds like you are not familiar with the processModel entry with attribute memoryLimit="60" as
default, it's in the machine.config file. thanks!
"Willy Denoyette [MVP]" <wi*************@telenet.be> wrote in message
news:O5*************@TK2MSFTNGP15.phx.gbl...
Again, you don't have to implement IDisposable when you don't deal with managed resources. What do you expect to do in your Dispose method? And No there is no documentation available on Safe points, because they don't

apply
here (at least not in the code snip you've posted).
I'm also not clear on what you mean with recycling the asp.net process,
is
this something you intend to do or is it something that you are
expecting to
be done automatically, anyway before the asp.net process recycles,
all application domains get unloaded, and this implies a GC run and a

finalizer
run, so all objects (still referenced too) will be collected , but even when
some objects aren't collected, all memory once allocated for the
process will return to the OS when the process ends. So what are you afraid of?

Willy.

"Zeng" <Ze******@hotmail.com> wrote in message
news:uX**************@tk2msftngp13.phx.gbl...
> Relying on IDisposable won't work easily in the multi-threading

scenarios.
> Since the memory required for each object is big, I have put them on
> static
> variable to share it among the servicing threads. Think of CMyClass is a > spell-grammar-checker that helps looking up things and provide

suggestions
> for correction for many users create their documents online. In this > scenario, looks like there is the only choice
> --> Make CMyClass disposable and create managing component (internal or > external to the class) just to coordinate when and which objects are

done
> just to call Dispose. This sounds like the intensive plumbing and
> error-prone approach that I was so used to with C++
>
> Conceptually, this is the drawback of a smart system, the programmer

knows
> what he/she needs to be done but can't change its behavior (which is

very
> very smart most of the time)
>
> By the way, where can I find a documentation about the safe-points?
> Wouldn't that be better that there is a call to wait for the system to be
> done with collection and there is a safe point in that method? And
is > there
> a safe point in the component that checks for memory usage and recycle the
> aspnet process when 60%(default) is reached?
>
>
>
> "billr" <bi***@discussions.microsoft.com> wrote in message
> news:3B**********************************@microsof t.com...
>> and just to add my two pennies worth ...
>>
>> Although you may call GC.Collect(), much the same as in Java when
you try
> to
>> force the VM to run garbage collection, it will still run at it's
>> earliest
>> convenience.
>>
>> During compilation, your code is injected with "safe points"
whereby the
> GC
>> can hijack the thread and take control to do its work. Now, when
you call
>> GC.Collect() your code might not be in a stable enough state for
the GC >> to
>> run, and the only way that the GC can know that it is safe to run is if >> it
>> has reached a "safe point".
>>
>> Generally speaking, it is bad practice to call GC.Collect() since you >> will
>> inadvertantly interrupt a perfectly (or near to) working system, and you
>> yourself can cause all sorts of naughtiness to occur.
>>
>> My choice of preference (as it is for a lot of developers) is to
>> implement
>> IDisposable.
>>
>> AND, yes, our code should be easily readable and left in a state
that >> renders it possible for future devlopers to look at it and see what is > going
>> on (for maintenance reasons, or whatever), however, designing our

classes
>> "off centre" just in case, the next developer doesn't know as much as us
> is a
>> pretty poor choice IMHO.
>>
>> --
>> Of all words of tongue and pen, the saddest are: "It might have
been" >>
>> Bill.Richards @ greyskin .co .uk
>> http://greyskin.co.uk
>>
>>
>> "Zeng" wrote:
>>
>> >
>> > I finally narrowed down my code to this situation, quite a few (not >> > all)
> of
>> > my CMyClass objects got hold up after each run of this function via the
>> > simple webpage that shows NumberEd editbox. My memory profile
shows > that
>> > those instances survive 3 rounds of GC collections - it's not what I >> > expected. In my real code, CMyClass occupies big amount of memory and
> they
>> > all share one stance of another class that I don't have enough
memory > hold
>> > more than a just a few in the memory. Notice that the finalizaer the
> my
>> > CMyClass makes a big difference in demonstrating this issue, w/o
it the
>> > problem doesn't exist. The interesting thing is if I run the

page > again,
>> > the old dangling ones got destroyed and the new ones become dangling. >> > Am
> I
>> > missing something about the GC? Do I need to explicitly implement and > call
>> > dispose for these classes instead of relying on GC to promptly

collect
> it?
>> > Apparently somehow these objects can survive the automatic
>> > collections...disposing it would help. Thanks for your comment and >> > help.
>> >
>> > internal class CMyClass
>> > {
>> > ArrayList m_array = new ArrayList( 50000 );
>> > private string m_idStr;
>> > private Guid m_guid;
>> > internal CMyClass( int n )
>> > {
>> > for( int i = 0; i < n; ++i )
>> > m_array.Add( Guid.NewGuid() );
>> >
>> > m_guid = Guid.NewGuid();
>> > m_idStr = m_guid.ToString();
>> > }
>> >
>> > internal Guid id
>> > {
>> > get{ return (Guid ) m_array[ 0 ]; }
>> > }
>> >
>> > ~CMyClass()
>> > {
>> > // Trace.Write( m_guid, m_idStr );
>> > }
>> >
>> > }
>> > private void RunBtn_Click(object sender, System.EventArgs e) >> > {
>> > ResultEd.Text = "";
>> > try
>> > {
>> >
>> > for( int i = 0; i < int.Parse( NumberEd.Text ); ++i ) >> > {
>> >
>> > Hashtable table = new Hashtable( 100 );
>> > ArrayList ids = new ArrayList( 10 );
>> > for( int j = 0; j < 10; ++j )
>> > {
>> > Guid id = Guid.NewGuid();
>> > table[ id ] = null;
>> > ids.Add( id );
>> > }
>> >
>> >
>> > for( int k=0; k < 10; ++k )
>> > {
>> > foreach( Guid id in ids )
>> > {
>> > table[ id ] = new CMyClass( 10 );
>> > }
>> >
>> > CMyClass myobj;
>> > foreach( Guid id in ids )
>> > {
>> > myobj = (CMyClass) table[ id ];
>> > myobj.id.ToString();
>> > }
>> > } // for k
>> > } // for
>> > }
>> > catch( Exception ex )
>> > {
>> > ResultEd.Text = ex.Message + "...CallSTack:" +
>> > ex.StackTrace;
>> > }
>> >
>> > GC.Collect();
>> > GC.WaitForPendingFinalizers();
>> > GC.Collect();
>> >
>> > GC.WaitForPendingFinalizers();
>> > GC.Collect();
>> >
>> > ResultEd.Text = "Done";
>> > }
>> >
>> >
>> >
>> >
>
>


Nov 17 '05 #21

P: n/a
From this paragraph:
Garbage collection is triggered in .NET either by application shutdown, heap exhaustion, or an explicit call GC.Collect(). With the exception of
application shutdown, however, garbage collection only occurs when the
execution path reaches a safe point.
Does that mean it's possible for my process to get recycled for reach memory
max% even though most of the memory counted as used is no longer needed by
my app and it is not freed because GC hasn't gotten a chance to do so
safely? If that's true, sounds to me that having a finalizer in my class or
not would only *reduce* the chance of that occuring, but not eliminating, is
that accessment accurate to you?

"billr" <bi***@discussions.microsoft.com> wrote in message
news:DA**********************************@microsof t.com... I guess it's time for me to make my apologies. The point of my mentioning
Safe Points was to illustrate the workings of the GC.

Safe Points are points in the code that have been identified as it being
safe for the GC to suspend ALL threads in order to do its thing.

A problem faced by the GC is that when compacting the heap it must make sure that it does not change the structure of the object graphs (internal
tree-like structures used for determining reachable/non-reachable objects
i.e. referenced/non-referenced objects), nor should it change the structure of the heap. In order to achieve this, the GC is responsible for maintaining object references (i.e. adjusting references within objects contained within the graphs), because of course, when an object is moved in the heap, any
existing references to that object will be invalid. The only safe way to cope with this is to suspend all application threads during garbage collection. It is for this reason that the JIT compiler inserts Safe Points into the code, i.e. points in the execution path that are safe for thread suspension.

Garbage collection occurs by the GC effectively "hijacking" the thread by
inserting a different return address from the safe point. When GC is
complete, .NET sends the thread back to its original return address and
normal execution continues.

Garbage collection is triggered in .NET either by application shutdown, heap exhaustion, or an explicit call GC.Collect(). With the exception of
application shutdown, however, garbage collection only occurs when the
execution path reaches a safe point.

IMPORTANT NOTE :
================

When the GC has determined that an object is in fact garbage, the first
thing it does is check the object's metadata, and if the object implements
Finalize(), instead of destroying the object, it is marked as reachable
(which is not what you want if you want your object to be destroyed
immediately) and is moved from its original graph to another graph called the "finalized queue". A seperate thread then iterates over the finalized queue invoking Finalize() on all objects contained therein; then -and only then-
are the objects removed from the queue and destroyed, hence freeing up its
heap space.

So, essentially, when you implement Finalize() you are telling the GC that
when the object is no longer referenced it is NOT SAFE for deletion YET, and Finalize() must first be invoked, which means that the object is not
destroyed for approximately two runs of garbage collection. It is for this
reason that deterministic finalization is recommended.

EXPLICIT garbage collection is not recommended becuase it is an expensive
operation involving scanning object graphs, thread suspension and resumption, thread context switches, and EXTENSIVE use of reflection to read the objects' metadata.

I hope that that clears up the confusion I might have injected into the
discussion, also, I hope it clears up why you should not declare a finalizer, even if there is no body. The simple act of declaring a finalizer ensures
that the object lives for longer than you might actually intend/require.

--
Of all words of tongue and pen, the saddest are: "It might have been"

Bill.Richards @ greyskin .co .uk
http://greyskin.co.uk
"Zeng" wrote:
I'm not sure on what you mean by "there is no documentation
available...because they don't apply here...". The existance of a document doesn't depend on what part of version of my code was posted. I appreciate your help looking into this for me, many people would just ignore posts and move on even they know the answer or have some comments, but I don't think we are going anywhere with it. My response was to BillR who proposes that I should be implementing the IDisposable.

It's the production environment, if the process get recycled, all my cache in the memory will have to be reloaded when it goes back up. That would
cause delay to the service that we want to provide. Sounds like you are not familiar with the processModel entry with attribute memoryLimit="60" as
default, it's in the machine.config file. thanks!
"Willy Denoyette [MVP]" <wi*************@telenet.be> wrote in message
news:O5*************@TK2MSFTNGP15.phx.gbl...
Again, you don't have to implement IDisposable when you don't deal with managed resources. What do you expect to do in your Dispose method? And No there is no documentation available on Safe points, because they don't

apply
here (at least not in the code snip you've posted).
I'm also not clear on what you mean with recycling the asp.net process,
is
this something you intend to do or is it something that you are
expecting to
be done automatically, anyway before the asp.net process recycles,
all application domains get unloaded, and this implies a GC run and a

finalizer
run, so all objects (still referenced too) will be collected , but even when
some objects aren't collected, all memory once allocated for the
process will return to the OS when the process ends. So what are you afraid of?

Willy.

"Zeng" <Ze******@hotmail.com> wrote in message
news:uX**************@tk2msftngp13.phx.gbl...
> Relying on IDisposable won't work easily in the multi-threading

scenarios.
> Since the memory required for each object is big, I have put them on
> static
> variable to share it among the servicing threads. Think of CMyClass is a > spell-grammar-checker that helps looking up things and provide

suggestions
> for correction for many users create their documents online. In this > scenario, looks like there is the only choice
> --> Make CMyClass disposable and create managing component (internal or > external to the class) just to coordinate when and which objects are

done
> just to call Dispose. This sounds like the intensive plumbing and
> error-prone approach that I was so used to with C++
>
> Conceptually, this is the drawback of a smart system, the programmer

knows
> what he/she needs to be done but can't change its behavior (which is

very
> very smart most of the time)
>
> By the way, where can I find a documentation about the safe-points?
> Wouldn't that be better that there is a call to wait for the system to be
> done with collection and there is a safe point in that method? And
is > there
> a safe point in the component that checks for memory usage and recycle the
> aspnet process when 60%(default) is reached?
>
>
>
> "billr" <bi***@discussions.microsoft.com> wrote in message
> news:3B**********************************@microsof t.com...
>> and just to add my two pennies worth ...
>>
>> Although you may call GC.Collect(), much the same as in Java when
you try
> to
>> force the VM to run garbage collection, it will still run at it's
>> earliest
>> convenience.
>>
>> During compilation, your code is injected with "safe points"
whereby the
> GC
>> can hijack the thread and take control to do its work. Now, when
you call
>> GC.Collect() your code might not be in a stable enough state for
the GC >> to
>> run, and the only way that the GC can know that it is safe to run is if >> it
>> has reached a "safe point".
>>
>> Generally speaking, it is bad practice to call GC.Collect() since you >> will
>> inadvertantly interrupt a perfectly (or near to) working system, and you
>> yourself can cause all sorts of naughtiness to occur.
>>
>> My choice of preference (as it is for a lot of developers) is to
>> implement
>> IDisposable.
>>
>> AND, yes, our code should be easily readable and left in a state
that >> renders it possible for future devlopers to look at it and see what is > going
>> on (for maintenance reasons, or whatever), however, designing our

classes
>> "off centre" just in case, the next developer doesn't know as much as us
> is a
>> pretty poor choice IMHO.
>>
>> --
>> Of all words of tongue and pen, the saddest are: "It might have
been" >>
>> Bill.Richards @ greyskin .co .uk
>> http://greyskin.co.uk
>>
>>
>> "Zeng" wrote:
>>
>> >
>> > I finally narrowed down my code to this situation, quite a few (not >> > all)
> of
>> > my CMyClass objects got hold up after each run of this function via the
>> > simple webpage that shows NumberEd editbox. My memory profile
shows > that
>> > those instances survive 3 rounds of GC collections - it's not what I >> > expected. In my real code, CMyClass occupies big amount of memory and
> they
>> > all share one stance of another class that I don't have enough
memory > hold
>> > more than a just a few in the memory. Notice that the finalizaer the
> my
>> > CMyClass makes a big difference in demonstrating this issue, w/o
it the
>> > problem doesn't exist. The interesting thing is if I run the

page > again,
>> > the old dangling ones got destroyed and the new ones become dangling. >> > Am
> I
>> > missing something about the GC? Do I need to explicitly implement and > call
>> > dispose for these classes instead of relying on GC to promptly

collect
> it?
>> > Apparently somehow these objects can survive the automatic
>> > collections...disposing it would help. Thanks for your comment and >> > help.
>> >
>> > internal class CMyClass
>> > {
>> > ArrayList m_array = new ArrayList( 50000 );
>> > private string m_idStr;
>> > private Guid m_guid;
>> > internal CMyClass( int n )
>> > {
>> > for( int i = 0; i < n; ++i )
>> > m_array.Add( Guid.NewGuid() );
>> >
>> > m_guid = Guid.NewGuid();
>> > m_idStr = m_guid.ToString();
>> > }
>> >
>> > internal Guid id
>> > {
>> > get{ return (Guid ) m_array[ 0 ]; }
>> > }
>> >
>> > ~CMyClass()
>> > {
>> > // Trace.Write( m_guid, m_idStr );
>> > }
>> >
>> > }
>> > private void RunBtn_Click(object sender, System.EventArgs e) >> > {
>> > ResultEd.Text = "";
>> > try
>> > {
>> >
>> > for( int i = 0; i < int.Parse( NumberEd.Text ); ++i ) >> > {
>> >
>> > Hashtable table = new Hashtable( 100 );
>> > ArrayList ids = new ArrayList( 10 );
>> > for( int j = 0; j < 10; ++j )
>> > {
>> > Guid id = Guid.NewGuid();
>> > table[ id ] = null;
>> > ids.Add( id );
>> > }
>> >
>> >
>> > for( int k=0; k < 10; ++k )
>> > {
>> > foreach( Guid id in ids )
>> > {
>> > table[ id ] = new CMyClass( 10 );
>> > }
>> >
>> > CMyClass myobj;
>> > foreach( Guid id in ids )
>> > {
>> > myobj = (CMyClass) table[ id ];
>> > myobj.id.ToString();
>> > }
>> > } // for k
>> > } // for
>> > }
>> > catch( Exception ex )
>> > {
>> > ResultEd.Text = ex.Message + "...CallSTack:" +
>> > ex.StackTrace;
>> > }
>> >
>> > GC.Collect();
>> > GC.WaitForPendingFinalizers();
>> > GC.Collect();
>> >
>> > GC.WaitForPendingFinalizers();
>> > GC.Collect();
>> >
>> > ResultEd.Text = "Done";
>> > }
>> >
>> >
>> >
>> >
>
>


Nov 17 '05 #22

P: n/a
I'm asking you the same question as I have asked BillR:

Is it possible for my process to get recycled because it reaches memory
max% even though most of the memory counted as used is no longer needed by
my app and it is not freed because GC hasn't gotten a chance to do so
safely? If that's true, sounds to me that having a finalizer in my class or
not would only *reduce* the chance of that occuring, but not *eliminate*, is
that accessment accurate to you?

By the way, I hope I don't need to correct all my mis-understanding what the
GC is meant for to raise that question.

"Willy Denoyette [MVP]" <wi*************@telenet.be> wrote in message
news:%2****************@TK2MSFTNGP12.phx.gbl...
Seems like you have a fundamental mis-understanding on what the GC is meant for and how it's actually performing.
The GC's task is, to collect the memory space occupied by non-reachable
objects and compact the generation it is actually collecting, so that a
contiguous free space remains in the heap to add new objects.
A full GC is a GC run that collects all generations, the current version of the CLR has 3 generational logical heaps plus a separate large object heap
(LOH), from code you can ask for a GC run by calling GC.Collect(n) where n
indicates the generation to end with, a collection always starts with
generation 0.
GC.Collect() collects all generations plus the LOH, that's why it's called a full collect.

However, it's NOT the task of the GC to bring down the heap size, that's the task of the CLR memory manager , or the hosting process memory manager (if
any) in close cooperation with the OS.

Your code sample needs at least two GC.Collect() calls, that's because you
have a Finalizer (destructor in C# parlance).
When an instance of a finalizable object gets instantiated, it's registered as finalizable.
When it is no longer rooted at the next GC run, it will be moved to the
finalizable queue, where it stays until after the finalizer has run, after
which it's removed from the finalizer queue and it becomes eligible for
collection.
Note that it's possible that not all finalizables are immediately finalized, all depends on the load of the system and the time the finalizer thread
spends finalizing objects. The finalizer thread can be suspended before all finalizer have run, that's why we say at LEAST 2 GC runs, and why we suggest against destructors in C#.

Willy.

PS I suggest you start reading these (somewhat outdated) articles , before
you start arguing about a subject you don't seem to fully understand.
http://msdn.microsoft.com/msdnmag/is...I/default.aspx
http://msdn.microsoft.com/msdnmag/is...2/default.aspx

"Zeng" <Ze******@hotmail.com> wrote in message
news:eq**************@TK2MSFTNGP14.phx.gbl...
From what I understand, Dispose method doesn't help freeing manage
resources, and that's consistent with what you are saying.

About the hosting process tries to do a full GC run before it recycles
based
on MemoryLimit%; I don't believe it at this point, if there is such thing as
full GC and it's doing what we expect, then it should have been exposed so we - developers - can call it when we need to bring down the heap size
immediately (of course we don't need this if full GC is actually possible privately to the framework, but I don't believe it). How many times
should
I try to call GC.Collect to free the dangling objects in my demo code?
And
if GC.Collect doesn't do what "Collect" means, what is its use? Purely
advertising?

Imagine somebody sell you a cabinet and there is knob on it, and he tells you that yes that's a knob but don't use it, you NEVER need or want to use it. If you actually never need to use it then it should be only for
decoration :) but that was only a speculation - and one day you decide to pull or turn it, and it doesn't do anything ... hahaha who is more insane, the person tries to use the knob or the person put the knob on the cabinet and didn't think it's for decoration??

"Willy Denoyette [MVP]" <wi*************@telenet.be> wrote in message
news:eA**************@TK2MSFTNGP10.phx.gbl...
Sorry what I meant was ""there is no documentation ... AND they don't

apply
here". If you need more info on GC safe points I'm afraid you'll have to look in the source code files of the CLR if you happen to have a Source

Code
License. Anyway, when your code calls GC.Collect it's always at a safe GC point, it's only when a GC is "induced" that it might get postponed when your code is not at a GC safe point.
What Billr proposed makes little sense in your case because your class

don't
own unmanaged resources, like DB connections, unmanaged memory OS handles etc..., it only consumes managed heap memory which is taken care of by
the
GC, there is no need to force collections by calling GC.Collect yourself. But if you really think you have to implement IDisposable, go ahead, but please tell us what you will do in your Dispose method.

I guess I'm more familiar with the process model than you might think.
The
asp.net hosting process recycles when it's Working Set exceeds the
memoryLimit% of total available memory, but the hosting process will try
to
survive first by forcing a full GC run, followed by an attempt to
reduce the
working set, then and ONLY when it's WS still exceeds the MemoryLimit%
it will recycle, else it simply continues to run.
In case the WS could not be reduced it's simply because an application
hosted in asp.net allocates too much memory or as a result of heap
fragmentation (take care when allocating many large objects (>85Kb)), or as
a result of a design error.
When it happens on a production system, it must be considered an

application
error , because the memoryLimit%, available system memory, number of

active
clients etc.. should have been defined during staging, when you
performed your load/stress testing and your workload modeling.

Willy.

"Zeng" <Ze******@hotmail.com> wrote in message
news:%2****************@TK2MSFTNGP09.phx.gbl...
> I'm not sure on what you mean by "there is no documentation
> available...because they don't apply here...". The existance of a
> document
> doesn't depend on what part of version of my code was posted. I
> appreciate
> your help looking into this for me, many people would just ignore posts > and
> move on even they know the answer or have some comments, but I don't

think
> we are going anywhere with it. My response was to BillR who proposes

that
> I
> should be implementing the IDisposable.
>
> It's the production environment, if the process get recycled, all my

cache
> in the memory will have to be reloaded when it goes back up. That
> would
> cause delay to the service that we want to provide. Sounds like you
> are
> not
> familiar with the processModel entry with attribute memoryLimit="60" as > default, it's in the machine.config file. thanks!
>
>
> "Willy Denoyette [MVP]" <wi*************@telenet.be> wrote in message
> news:O5*************@TK2MSFTNGP15.phx.gbl...
>> Again, you don't have to implement IDisposable when you don't deal
>> with
>> managed resources. What do you expect to do in your Dispose method?
>> And
>> No
>> there is no documentation available on Safe points, because they don't > apply
>> here (at least not in the code snip you've posted).
>> I'm also not clear on what you mean with recycling the asp.net

process,
> is
>> this something you intend to do or is it something that you are

expecting
> to
>> be done automatically, anyway before the asp.net process recycles,
>> all
>> application domains get unloaded, and this implies a GC run and a
> finalizer
>> run, so all objects (still referenced too) will be collected , but
>> even
> when
>> some objects aren't collected, all memory once allocated for the

process
>> will return to the OS when the process ends. So what are you afraid
>> of?
>>
>>
>> Willy.
>>
>> "Zeng" <Ze******@hotmail.com> wrote in message
>> news:uX**************@tk2msftngp13.phx.gbl...
>> > Relying on IDisposable won't work easily in the multi-threading
> scenarios.
>> > Since the memory required for each object is big, I have put them on >> > static
>> > variable to share it among the servicing threads. Think of CMyClass is
>> > a
>> > spell-grammar-checker that helps looking up things and provide
> suggestions
>> > for correction for many users create their documents online. In
>> > this
>> > scenario, looks like there is the only choice
>> > --> Make CMyClass disposable and create managing component
(internal or
>> > external to the class) just to coordinate when and which objects
are > done
>> > just to call Dispose. This sounds like the intensive plumbing and
>> > error-prone approach that I was so used to with C++
>> >
>> > Conceptually, this is the drawback of a smart system, the programmer > knows
>> > what he/she needs to be done but can't change its behavior (which is > very
>> > very smart most of the time)
>> >
>> > By the way, where can I find a documentation about the safe-points? >> > Wouldn't that be better that there is a call to wait for the system to
> be
>> > done with collection and there is a safe point in that method? And
>> > is
>> > there
>> > a safe point in the component that checks for memory usage and

recycle
> the
>> > aspnet process when 60%(default) is reached?
>> >
>> >
>> >
>> > "billr" <bi***@discussions.microsoft.com> wrote in message
>> > news:3B**********************************@microsof t.com...
>> >> and just to add my two pennies worth ...
>> >>
>> >> Although you may call GC.Collect(), much the same as in Java when

you
> try
>> > to
>> >> force the VM to run garbage collection, it will still run at it's
>> >> earliest
>> >> convenience.
>> >>
>> >> During compilation, your code is injected with "safe points"
>> >> whereby
> the
>> > GC
>> >> can hijack the thread and take control to do its work. Now, when
>> >> you
> call
>> >> GC.Collect() your code might not be in a stable enough state for
>> >> the
>> >> GC
>> >> to
>> >> run, and the only way that the GC can know that it is safe to run
>> >> is
>> >> if
>> >> it
>> >> has reached a "safe point".
>> >>
>> >> Generally speaking, it is bad practice to call GC.Collect() since

you
>> >> will
>> >> inadvertantly interrupt a perfectly (or near to) working system,
>> >> and
> you
>> >> yourself can cause all sorts of naughtiness to occur.
>> >>
>> >> My choice of preference (as it is for a lot of developers) is to
>> >> implement
>> >> IDisposable.
>> >>
>> >> AND, yes, our code should be easily readable and left in a state

that
>> >> renders it possible for future devlopers to look at it and see
what is
>> > going
>> >> on (for maintenance reasons, or whatever), however, designing our
> classes
>> >> "off centre" just in case, the next developer doesn't know as
much as
> us
>> > is a
>> >> pretty poor choice IMHO.
>> >>
>> >> --
>> >> Of all words of tongue and pen, the saddest are: "It might have

been"
>> >>
>> >> Bill.Richards @ greyskin .co .uk
>> >> http://greyskin.co.uk
>> >>
>> >>
>> >> "Zeng" wrote:
>> >>
>> >> >
>> >> > I finally narrowed down my code to this situation, quite a few

(not
>> >> > all)
>> > of
>> >> > my CMyClass objects got hold up after each run of this function

via
> the
>> >> > simple webpage that shows NumberEd editbox. My memory profile

shows
>> > that
>> >> > those instances survive 3 rounds of GC collections - it's not
>> >> > what

I
>> >> > expected. In my real code, CMyClass occupies big amount of
>> >> > memory
> and
>> > they
>> >> > all share one stance of another class that I don't have enough
>> >> > memory
>> > hold
>> >> > more than a just a few in the memory. Notice that the
>> >> > finalizaer
> the
>> > my
>> >> > CMyClass makes a big difference in demonstrating this issue,
w/o it
> the
>> >> > problem doesn't exist. The interesting thing is if I run the
>> >> > page
>> > again,
>> >> > the old dangling ones got destroyed and the new ones become
>> >> > dangling.
>> >> > Am
>> > I
>> >> > missing something about the GC? Do I need to explicitly
implement >> >> > and
>> > call
>> >> > dispose for these classes instead of relying on GC to promptly
> collect
>> > it?
>> >> > Apparently somehow these objects can survive the automatic
>> >> > collections...disposing it would help. Thanks for your comment
>> >> > and
>> >> > help.
>> >> >
>> >> > internal class CMyClass
>> >> > {
>> >> > ArrayList m_array = new ArrayList( 50000 );
>> >> > private string m_idStr;
>> >> > private Guid m_guid;
>> >> > internal CMyClass( int n )
>> >> > {
>> >> > for( int i = 0; i < n; ++i )
>> >> > m_array.Add( Guid.NewGuid() );
>> >> >
>> >> > m_guid = Guid.NewGuid();
>> >> > m_idStr = m_guid.ToString();
>> >> > }
>> >> >
>> >> > internal Guid id
>> >> > {
>> >> > get{ return (Guid ) m_array[ 0 ]; }
>> >> > }
>> >> >
>> >> > ~CMyClass()
>> >> > {
>> >> > // Trace.Write( m_guid, m_idStr );
>> >> > }
>> >> >
>> >> > }
>> >> > private void RunBtn_Click(object sender,

System.EventArgs e)
>> >> > {
>> >> > ResultEd.Text = "";
>> >> > try
>> >> > {
>> >> >
>> >> > for( int i = 0; i < int.Parse( NumberEd.Text );
>> >> > ++i )
>> >> > {
>> >> >
>> >> > Hashtable table = new Hashtable( 100 );
>> >> > ArrayList ids = new ArrayList( 10 );
>> >> > for( int j = 0; j < 10; ++j )
>> >> > {
>> >> > Guid id = Guid.NewGuid();
>> >> > table[ id ] = null;
>> >> > ids.Add( id );
>> >> > }
>> >> >
>> >> >
>> >> > for( int k=0; k < 10; ++k )
>> >> > {
>> >> > foreach( Guid id in ids )
>> >> > {
>> >> > table[ id ] = new CMyClass( 10 );
>> >> > }
>> >> >
>> >> > CMyClass myobj;
>> >> > foreach( Guid id in ids )
>> >> > {
>> >> > myobj = (CMyClass) table[ id ];
>> >> > myobj.id.ToString();
>> >> > }
>> >> > } // for k
>> >> > } // for
>> >> > }
>> >> > catch( Exception ex )
>> >> > {
>> >> > ResultEd.Text = ex.Message + "...CallSTack:" +
>> >> > ex.StackTrace;
>> >> > }
>> >> >
>> >> > GC.Collect();
>> >> > GC.WaitForPendingFinalizers();
>> >> > GC.Collect();
>> >> >
>> >> > GC.WaitForPendingFinalizers();
>> >> > GC.Collect();
>> >> >
>> >> > ResultEd.Text = "Done";
>> >> > }
>> >> >
>> >> >
>> >> >
>> >> >
>> >
>> >
>>
>>
>
>



Nov 17 '05 #23

P: n/a
I'm asking you the same question as I have asked BillR:

Is it possible for my process to get recycled because it reaches memory
max% even though most of the memory counted as used is no longer needed by
my app and it is not freed because GC hasn't gotten a chance to do so
safely? If that's true, sounds to me that having a finalizer in my class or
not would only *reduce* the chance of that occuring, but not *eliminate*, is
that accessment accurate to you?

By the way, I hope I don't need to correct all my mis-understanding what the
GC is meant for to raise that question.

"Willy Denoyette [MVP]" <wi*************@telenet.be> wrote in message
news:%2****************@TK2MSFTNGP12.phx.gbl...
Seems like you have a fundamental mis-understanding on what the GC is meant for and how it's actually performing.
The GC's task is, to collect the memory space occupied by non-reachable
objects and compact the generation it is actually collecting, so that a
contiguous free space remains in the heap to add new objects.
A full GC is a GC run that collects all generations, the current version of the CLR has 3 generational logical heaps plus a separate large object heap
(LOH), from code you can ask for a GC run by calling GC.Collect(n) where n
indicates the generation to end with, a collection always starts with
generation 0.
GC.Collect() collects all generations plus the LOH, that's why it's called a full collect.

However, it's NOT the task of the GC to bring down the heap size, that's the task of the CLR memory manager , or the hosting process memory manager (if
any) in close cooperation with the OS.

Your code sample needs at least two GC.Collect() calls, that's because you
have a Finalizer (destructor in C# parlance).
When an instance of a finalizable object gets instantiated, it's registered as finalizable.
When it is no longer rooted at the next GC run, it will be moved to the
finalizable queue, where it stays until after the finalizer has run, after
which it's removed from the finalizer queue and it becomes eligible for
collection.
Note that it's possible that not all finalizables are immediately finalized, all depends on the load of the system and the time the finalizer thread
spends finalizing objects. The finalizer thread can be suspended before all finalizer have run, that's why we say at LEAST 2 GC runs, and why we suggest against destructors in C#.

Willy.

PS I suggest you start reading these (somewhat outdated) articles , before
you start arguing about a subject you don't seem to fully understand.
http://msdn.microsoft.com/msdnmag/is...I/default.aspx
http://msdn.microsoft.com/msdnmag/is...2/default.aspx

"Zeng" <Ze******@hotmail.com> wrote in message
news:eq**************@TK2MSFTNGP14.phx.gbl...
From what I understand, Dispose method doesn't help freeing manage
resources, and that's consistent with what you are saying.

About the hosting process tries to do a full GC run before it recycles
based
on MemoryLimit%; I don't believe it at this point, if there is such thing as
full GC and it's doing what we expect, then it should have been exposed so we - developers - can call it when we need to bring down the heap size
immediately (of course we don't need this if full GC is actually possible privately to the framework, but I don't believe it). How many times
should
I try to call GC.Collect to free the dangling objects in my demo code?
And
if GC.Collect doesn't do what "Collect" means, what is its use? Purely
advertising?

Imagine somebody sell you a cabinet and there is knob on it, and he tells you that yes that's a knob but don't use it, you NEVER need or want to use it. If you actually never need to use it then it should be only for
decoration :) but that was only a speculation - and one day you decide to pull or turn it, and it doesn't do anything ... hahaha who is more insane, the person tries to use the knob or the person put the knob on the cabinet and didn't think it's for decoration??

"Willy Denoyette [MVP]" <wi*************@telenet.be> wrote in message
news:eA**************@TK2MSFTNGP10.phx.gbl...
Sorry what I meant was ""there is no documentation ... AND they don't

apply
here". If you need more info on GC safe points I'm afraid you'll have to look in the source code files of the CLR if you happen to have a Source

Code
License. Anyway, when your code calls GC.Collect it's always at a safe GC point, it's only when a GC is "induced" that it might get postponed when your code is not at a GC safe point.
What Billr proposed makes little sense in your case because your class

don't
own unmanaged resources, like DB connections, unmanaged memory OS handles etc..., it only consumes managed heap memory which is taken care of by
the
GC, there is no need to force collections by calling GC.Collect yourself. But if you really think you have to implement IDisposable, go ahead, but please tell us what you will do in your Dispose method.

I guess I'm more familiar with the process model than you might think.
The
asp.net hosting process recycles when it's Working Set exceeds the
memoryLimit% of total available memory, but the hosting process will try
to
survive first by forcing a full GC run, followed by an attempt to
reduce the
working set, then and ONLY when it's WS still exceeds the MemoryLimit%
it will recycle, else it simply continues to run.
In case the WS could not be reduced it's simply because an application
hosted in asp.net allocates too much memory or as a result of heap
fragmentation (take care when allocating many large objects (>85Kb)), or as
a result of a design error.
When it happens on a production system, it must be considered an

application
error , because the memoryLimit%, available system memory, number of

active
clients etc.. should have been defined during staging, when you
performed your load/stress testing and your workload modeling.

Willy.

"Zeng" <Ze******@hotmail.com> wrote in message
news:%2****************@TK2MSFTNGP09.phx.gbl...
> I'm not sure on what you mean by "there is no documentation
> available...because they don't apply here...". The existance of a
> document
> doesn't depend on what part of version of my code was posted. I
> appreciate
> your help looking into this for me, many people would just ignore posts > and
> move on even they know the answer or have some comments, but I don't

think
> we are going anywhere with it. My response was to BillR who proposes

that
> I
> should be implementing the IDisposable.
>
> It's the production environment, if the process get recycled, all my

cache
> in the memory will have to be reloaded when it goes back up. That
> would
> cause delay to the service that we want to provide. Sounds like you
> are
> not
> familiar with the processModel entry with attribute memoryLimit="60" as > default, it's in the machine.config file. thanks!
>
>
> "Willy Denoyette [MVP]" <wi*************@telenet.be> wrote in message
> news:O5*************@TK2MSFTNGP15.phx.gbl...
>> Again, you don't have to implement IDisposable when you don't deal
>> with
>> managed resources. What do you expect to do in your Dispose method?
>> And
>> No
>> there is no documentation available on Safe points, because they don't > apply
>> here (at least not in the code snip you've posted).
>> I'm also not clear on what you mean with recycling the asp.net

process,
> is
>> this something you intend to do or is it something that you are

expecting
> to
>> be done automatically, anyway before the asp.net process recycles,
>> all
>> application domains get unloaded, and this implies a GC run and a
> finalizer
>> run, so all objects (still referenced too) will be collected , but
>> even
> when
>> some objects aren't collected, all memory once allocated for the

process
>> will return to the OS when the process ends. So what are you afraid
>> of?
>>
>>
>> Willy.
>>
>> "Zeng" <Ze******@hotmail.com> wrote in message
>> news:uX**************@tk2msftngp13.phx.gbl...
>> > Relying on IDisposable won't work easily in the multi-threading
> scenarios.
>> > Since the memory required for each object is big, I have put them on >> > static
>> > variable to share it among the servicing threads. Think of CMyClass is
>> > a
>> > spell-grammar-checker that helps looking up things and provide
> suggestions
>> > for correction for many users create their documents online. In
>> > this
>> > scenario, looks like there is the only choice
>> > --> Make CMyClass disposable and create managing component
(internal or
>> > external to the class) just to coordinate when and which objects
are > done
>> > just to call Dispose. This sounds like the intensive plumbing and
>> > error-prone approach that I was so used to with C++
>> >
>> > Conceptually, this is the drawback of a smart system, the programmer > knows
>> > what he/she needs to be done but can't change its behavior (which is > very
>> > very smart most of the time)
>> >
>> > By the way, where can I find a documentation about the safe-points? >> > Wouldn't that be better that there is a call to wait for the system to
> be
>> > done with collection and there is a safe point in that method? And
>> > is
>> > there
>> > a safe point in the component that checks for memory usage and

recycle
> the
>> > aspnet process when 60%(default) is reached?
>> >
>> >
>> >
>> > "billr" <bi***@discussions.microsoft.com> wrote in message
>> > news:3B**********************************@microsof t.com...
>> >> and just to add my two pennies worth ...
>> >>
>> >> Although you may call GC.Collect(), much the same as in Java when

you
> try
>> > to
>> >> force the VM to run garbage collection, it will still run at it's
>> >> earliest
>> >> convenience.
>> >>
>> >> During compilation, your code is injected with "safe points"
>> >> whereby
> the
>> > GC
>> >> can hijack the thread and take control to do its work. Now, when
>> >> you
> call
>> >> GC.Collect() your code might not be in a stable enough state for
>> >> the
>> >> GC
>> >> to
>> >> run, and the only way that the GC can know that it is safe to run
>> >> is
>> >> if
>> >> it
>> >> has reached a "safe point".
>> >>
>> >> Generally speaking, it is bad practice to call GC.Collect() since

you
>> >> will
>> >> inadvertantly interrupt a perfectly (or near to) working system,
>> >> and
> you
>> >> yourself can cause all sorts of naughtiness to occur.
>> >>
>> >> My choice of preference (as it is for a lot of developers) is to
>> >> implement
>> >> IDisposable.
>> >>
>> >> AND, yes, our code should be easily readable and left in a state

that
>> >> renders it possible for future devlopers to look at it and see
what is
>> > going
>> >> on (for maintenance reasons, or whatever), however, designing our
> classes
>> >> "off centre" just in case, the next developer doesn't know as
much as
> us
>> > is a
>> >> pretty poor choice IMHO.
>> >>
>> >> --
>> >> Of all words of tongue and pen, the saddest are: "It might have

been"
>> >>
>> >> Bill.Richards @ greyskin .co .uk
>> >> http://greyskin.co.uk
>> >>
>> >>
>> >> "Zeng" wrote:
>> >>
>> >> >
>> >> > I finally narrowed down my code to this situation, quite a few

(not
>> >> > all)
>> > of
>> >> > my CMyClass objects got hold up after each run of this function

via
> the
>> >> > simple webpage that shows NumberEd editbox. My memory profile

shows
>> > that
>> >> > those instances survive 3 rounds of GC collections - it's not
>> >> > what

I
>> >> > expected. In my real code, CMyClass occupies big amount of
>> >> > memory
> and
>> > they
>> >> > all share one stance of another class that I don't have enough
>> >> > memory
>> > hold
>> >> > more than a just a few in the memory. Notice that the
>> >> > finalizaer
> the
>> > my
>> >> > CMyClass makes a big difference in demonstrating this issue,
w/o it
> the
>> >> > problem doesn't exist. The interesting thing is if I run the
>> >> > page
>> > again,
>> >> > the old dangling ones got destroyed and the new ones become
>> >> > dangling.
>> >> > Am
>> > I
>> >> > missing something about the GC? Do I need to explicitly
implement >> >> > and
>> > call
>> >> > dispose for these classes instead of relying on GC to promptly
> collect
>> > it?
>> >> > Apparently somehow these objects can survive the automatic
>> >> > collections...disposing it would help. Thanks for your comment
>> >> > and
>> >> > help.
>> >> >
>> >> > internal class CMyClass
>> >> > {
>> >> > ArrayList m_array = new ArrayList( 50000 );
>> >> > private string m_idStr;
>> >> > private Guid m_guid;
>> >> > internal CMyClass( int n )
>> >> > {
>> >> > for( int i = 0; i < n; ++i )
>> >> > m_array.Add( Guid.NewGuid() );
>> >> >
>> >> > m_guid = Guid.NewGuid();
>> >> > m_idStr = m_guid.ToString();
>> >> > }
>> >> >
>> >> > internal Guid id
>> >> > {
>> >> > get{ return (Guid ) m_array[ 0 ]; }
>> >> > }
>> >> >
>> >> > ~CMyClass()
>> >> > {
>> >> > // Trace.Write( m_guid, m_idStr );
>> >> > }
>> >> >
>> >> > }
>> >> > private void RunBtn_Click(object sender,

System.EventArgs e)
>> >> > {
>> >> > ResultEd.Text = "";
>> >> > try
>> >> > {
>> >> >
>> >> > for( int i = 0; i < int.Parse( NumberEd.Text );
>> >> > ++i )
>> >> > {
>> >> >
>> >> > Hashtable table = new Hashtable( 100 );
>> >> > ArrayList ids = new ArrayList( 10 );
>> >> > for( int j = 0; j < 10; ++j )
>> >> > {
>> >> > Guid id = Guid.NewGuid();
>> >> > table[ id ] = null;
>> >> > ids.Add( id );
>> >> > }
>> >> >
>> >> >
>> >> > for( int k=0; k < 10; ++k )
>> >> > {
>> >> > foreach( Guid id in ids )
>> >> > {
>> >> > table[ id ] = new CMyClass( 10 );
>> >> > }
>> >> >
>> >> > CMyClass myobj;
>> >> > foreach( Guid id in ids )
>> >> > {
>> >> > myobj = (CMyClass) table[ id ];
>> >> > myobj.id.ToString();
>> >> > }
>> >> > } // for k
>> >> > } // for
>> >> > }
>> >> > catch( Exception ex )
>> >> > {
>> >> > ResultEd.Text = ex.Message + "...CallSTack:" +
>> >> > ex.StackTrace;
>> >> > }
>> >> >
>> >> > GC.Collect();
>> >> > GC.WaitForPendingFinalizers();
>> >> > GC.Collect();
>> >> >
>> >> > GC.WaitForPendingFinalizers();
>> >> > GC.Collect();
>> >> >
>> >> > ResultEd.Text = "Done";
>> >> > }
>> >> >
>> >> >
>> >> >
>> >> >
>> >
>> >
>>
>>
>
>



Nov 17 '05 #24

P: n/a
That's strange, not too long ago Willy sounded so knowledgable about this
subject and almost like a salesman, now I haven't heard anything from him.
From this I can conclude:

1) Somehow Willy wouldn't dare to admit the truth that GC design and/or
implementation is messed up in this aspect. Hope he's not one of those
"bright" guys that Jon Shemitz referred to as responsible for GC
design/implementation.
2) GC is not releasing unused memory promptly and occasionally it is the
main cause for the process to get shutdown and recycled
2) GC is messing up another one. In the past I also found that that the LOH
(large object heap) gets fragmented gradually and the gap in between each
useful blocks might not ever get to be useful until the whole process gets
recycled (shutdown) because the total amount of used memory reaching max%.
The reason is GC never spends cpu cycles to compact it even before the
process recycles itself.
3) GC.Collect() has no useful purpose other than for decoration (marketing)
because calling it is bad - no one should ever call it, calling it doesn't
do what the name "Collect" suggests anyway. There is no reason for any app
to call it.

"Zeng" <Ze******@hotmail.com> wrote in message
news:ep**************@TK2MSFTNGP11.phx.gbl...
I'm asking you the same question as I have asked BillR:

Is it possible for my process to get recycled because it reaches memory
max% even though most of the memory counted as used is no longer needed by
my app and it is not freed because GC hasn't gotten a chance to do so
safely? If that's true, sounds to me that having a finalizer in my class or not would only *reduce* the chance of that occuring, but not *eliminate*, is that accessment accurate to you?

By the way, I hope I don't need to correct all my mis-understanding what the GC is meant for to raise that question.

"Willy Denoyette [MVP]" <wi*************@telenet.be> wrote in message
news:%2****************@TK2MSFTNGP12.phx.gbl...
Seems like you have a fundamental mis-understanding on what the GC is meant
for and how it's actually performing.
The GC's task is, to collect the memory space occupied by non-reachable
objects and compact the generation it is actually collecting, so that a
contiguous free space remains in the heap to add new objects.
A full GC is a GC run that collects all generations, the current version

of
the CLR has 3 generational logical heaps plus a separate large object heap
(LOH), from code you can ask for a GC run by calling GC.Collect(n) where n indicates the generation to end with, a collection always starts with
generation 0.
GC.Collect() collects all generations plus the LOH, that's why it's called a
full collect.

However, it's NOT the task of the GC to bring down the heap size, that's the
task of the CLR memory manager , or the hosting process memory manager

(if any) in close cooperation with the OS.

Your code sample needs at least two GC.Collect() calls, that's because you have a Finalizer (destructor in C# parlance).
When an instance of a finalizable object gets instantiated, it's

registered
as finalizable.
When it is no longer rooted at the next GC run, it will be moved to the
finalizable queue, where it stays until after the finalizer has run, after which it's removed from the finalizer queue and it becomes eligible for
collection.
Note that it's possible that not all finalizables are immediately

finalized,
all depends on the load of the system and the time the finalizer thread
spends finalizing objects. The finalizer thread can be suspended before

all
finalizer have run, that's why we say at LEAST 2 GC runs, and why we

suggest
against destructors in C#.

Willy.

PS I suggest you start reading these (somewhat outdated) articles , before you start arguing about a subject you don't seem to fully understand.
http://msdn.microsoft.com/msdnmag/is...I/default.aspx
http://msdn.microsoft.com/msdnmag/is...2/default.aspx

"Zeng" <Ze******@hotmail.com> wrote in message
news:eq**************@TK2MSFTNGP14.phx.gbl...
From what I understand, Dispose method doesn't help freeing manage
resources, and that's consistent with what you are saying.

About the hosting process tries to do a full GC run before it recycles
based
on MemoryLimit%; I don't believe it at this point, if there is such

thing as
full GC and it's doing what we expect, then it should have been exposed so
we - developers - can call it when we need to bring down the heap size
immediately (of course we don't need this if full GC is actually possible privately to the framework, but I don't believe it). How many times
should
I try to call GC.Collect to free the dangling objects in my demo code?
And
if GC.Collect doesn't do what "Collect" means, what is its use? Purely
advertising?

Imagine somebody sell you a cabinet and there is knob on it, and he tells you that yes that's a knob but don't use it, you NEVER need or want to use it. If you actually never need to use it then it should be only for
decoration :) but that was only a speculation - and one day you
decide
to pull or turn it, and it doesn't do anything ... hahaha who is more insane, the person tries to use the knob or the person put the knob on the cabinet and didn't think it's for decoration??

"Willy Denoyette [MVP]" <wi*************@telenet.be> wrote in message
news:eA**************@TK2MSFTNGP10.phx.gbl...
> Sorry what I meant was ""there is no documentation ... AND they don't
apply
> here". If you need more info on GC safe points I'm afraid you'll have to> look in the source code files of the CLR if you happen to have a
Source Code
> License. Anyway, when your code calls GC.Collect it's always at a safe
GC> point, it's only when a GC is "induced" that it might get postponed when> your code is not at a GC safe point.
> What Billr proposed makes little sense in your case because your
class don't
> own unmanaged resources, like DB connections, unmanaged memory OS
handles> etc..., it only consumes managed heap memory which is taken care of by> the
> GC, there is no need to force collections by calling GC.Collect yourself.> But if you really think you have to implement IDisposable, go ahead, but> please tell us what you will do in your Dispose method.
>
> I guess I'm more familiar with the process model than you might think.> The
> asp.net hosting process recycles when it's Working Set exceeds the
> memoryLimit% of total available memory, but the hosting process will try to
> survive first by forcing a full GC run, followed by an attempt to reduce the
> working set, then and ONLY when it's WS still exceeds the MemoryLimit% it
> will recycle, else it simply continues to run.
> In case the WS could not be reduced it's simply because an
application> hosted in asp.net allocates too much memory or as a result of heap
> fragmentation (take care when allocating many large objects (>85Kb)),
or as
> a result of a design error.
> When it happens on a production system, it must be considered an
application
> error , because the memoryLimit%, available system memory, number of
active
> clients etc.. should have been defined during staging, when you performed> your load/stress testing and your workload modeling.
>
> Willy.
>
> "Zeng" <Ze******@hotmail.com> wrote in message
> news:%2****************@TK2MSFTNGP09.phx.gbl...
> > I'm not sure on what you mean by "there is no documentation
> > available...because they don't apply here...". The existance of a
> > document
> > doesn't depend on what part of version of my code was posted. I
> > appreciate
> > your help looking into this for me, many people would just ignore posts> > and
> > move on even they know the answer or have some comments, but I don't think
> > we are going anywhere with it. My response was to BillR who proposes that
> > I
> > should be implementing the IDisposable.
> >
> > It's the production environment, if the process get recycled, all my cache
> > in the memory will have to be reloaded when it goes back up. That
> > would
> > cause delay to the service that we want to provide. Sounds like you> > are
> > not
> > familiar with the processModel entry with attribute memoryLimit="60" as
> > default, it's in the machine.config file. thanks!
> >
> >
> > "Willy Denoyette [MVP]" <wi*************@telenet.be> wrote in
message> > news:O5*************@TK2MSFTNGP15.phx.gbl...
> >> Again, you don't have to implement IDisposable when you don't deal
> >> with
> >> managed resources. What do you expect to do in your Dispose method?> >> And
> >> No
> >> there is no documentation available on Safe points, because they
don't> > apply
> >> here (at least not in the code snip you've posted).
> >> I'm also not clear on what you mean with recycling the asp.net
process,
> > is
> >> this something you intend to do or is it something that you are
expecting
> > to
> >> be done automatically, anyway before the asp.net process recycles,> >> all
> >> application domains get unloaded, and this implies a GC run and a
> > finalizer
> >> run, so all objects (still referenced too) will be collected , but
> >> even
> > when
> >> some objects aren't collected, all memory once allocated for the
process
> >> will return to the OS when the process ends. So what are you afraid> >> of?
> >>
> >>
> >> Willy.
> >>
> >> "Zeng" <Ze******@hotmail.com> wrote in message
> >> news:uX**************@tk2msftngp13.phx.gbl...
> >> > Relying on IDisposable won't work easily in the multi-threading
> > scenarios.
> >> > Since the memory required for each object is big, I have put them on
> >> > static
> >> > variable to share it among the servicing threads. Think of CMyClass is
> >> > a
> >> > spell-grammar-checker that helps looking up things and provide
> > suggestions
> >> > for correction for many users create their documents online. In
> >> > this
> >> > scenario, looks like there is the only choice
> >> > --> Make CMyClass disposable and create managing component (internal or
> >> > external to the class) just to coordinate when and which objects are> > done
> >> > just to call Dispose. This sounds like the intensive plumbing
and> >> > error-prone approach that I was so used to with C++
> >> >
> >> > Conceptually, this is the drawback of a smart system, the
programmer> > knows
> >> > what he/she needs to be done but can't change its behavior (which is
> > very
> >> > very smart most of the time)
> >> >
> >> > By the way, where can I find a documentation about the safe-points?> >> > Wouldn't that be better that there is a call to wait for the system to
> > be
> >> > done with collection and there is a safe point in that method?
And> >> > is
> >> > there
> >> > a safe point in the component that checks for memory usage and
recycle
> > the
> >> > aspnet process when 60%(default) is reached?
> >> >
> >> >
> >> >
> >> > "billr" <bi***@discussions.microsoft.com> wrote in message
> >> > news:3B**********************************@microsof t.com...
> >> >> and just to add my two pennies worth ...
> >> >>
> >> >> Although you may call GC.Collect(), much the same as in Java when you
> > try
> >> > to
> >> >> force the VM to run garbage collection, it will still run at it's> >> >> earliest
> >> >> convenience.
> >> >>
> >> >> During compilation, your code is injected with "safe points"
> >> >> whereby
> > the
> >> > GC
> >> >> can hijack the thread and take control to do its work. Now, when> >> >> you
> > call
> >> >> GC.Collect() your code might not be in a stable enough state for> >> >> the
> >> >> GC
> >> >> to
> >> >> run, and the only way that the GC can know that it is safe to run> >> >> is
> >> >> if
> >> >> it
> >> >> has reached a "safe point".
> >> >>
> >> >> Generally speaking, it is bad practice to call GC.Collect() since you
> >> >> will
> >> >> inadvertantly interrupt a perfectly (or near to) working system,> >> >> and
> > you
> >> >> yourself can cause all sorts of naughtiness to occur.
> >> >>
> >> >> My choice of preference (as it is for a lot of developers) is to> >> >> implement
> >> >> IDisposable.
> >> >>
> >> >> AND, yes, our code should be easily readable and left in a state that
> >> >> renders it possible for future devlopers to look at it and see

what is
> >> > going
> >> >> on (for maintenance reasons, or whatever), however, designing our> > classes
> >> >> "off centre" just in case, the next developer doesn't know as much as
> > us
> >> > is a
> >> >> pretty poor choice IMHO.
> >> >>
> >> >> --
> >> >> Of all words of tongue and pen, the saddest are: "It might have
been"
> >> >>
> >> >> Bill.Richards @ greyskin .co .uk
> >> >> http://greyskin.co.uk
> >> >>
> >> >>
> >> >> "Zeng" wrote:
> >> >>
> >> >> >
> >> >> > I finally narrowed down my code to this situation, quite a few (not
> >> >> > all)
> >> > of
> >> >> > my CMyClass objects got hold up after each run of this function via
> > the
> >> >> > simple webpage that shows NumberEd editbox. My memory profile shows
> >> > that
> >> >> > those instances survive 3 rounds of GC collections - it's not
> >> >> > what
I
> >> >> > expected. In my real code, CMyClass occupies big amount of
> >> >> > memory
> > and
> >> > they
> >> >> > all share one stance of another class that I don't have enough> >> >> > memory
> >> > hold
> >> >> > more than a just a few in the memory. Notice that the
> >> >> > finalizaer
> > the
> >> > my
> >> >> > CMyClass makes a big difference in demonstrating this issue, w/o it
> > the
> >> >> > problem doesn't exist. The interesting thing is if I run the
> >> >> > page
> >> > again,
> >> >> > the old dangling ones got destroyed and the new ones become
> >> >> > dangling.
> >> >> > Am
> >> > I
> >> >> > missing something about the GC? Do I need to explicitly implement> >> >> > and
> >> > call
> >> >> > dispose for these classes instead of relying on GC to promptly> > collect
> >> > it?
> >> >> > Apparently somehow these objects can survive the automatic
> >> >> > collections...disposing it would help. Thanks for your comment> >> >> > and
> >> >> > help.
> >> >> >
> >> >> > internal class CMyClass
> >> >> > {
> >> >> > ArrayList m_array = new ArrayList( 50000 );
> >> >> > private string m_idStr;
> >> >> > private Guid m_guid;
> >> >> > internal CMyClass( int n )
> >> >> > {
> >> >> > for( int i = 0; i < n; ++i )
> >> >> > m_array.Add( Guid.NewGuid() );
> >> >> >
> >> >> > m_guid = Guid.NewGuid();
> >> >> > m_idStr = m_guid.ToString();
> >> >> > }
> >> >> >
> >> >> > internal Guid id
> >> >> > {
> >> >> > get{ return (Guid ) m_array[ 0 ]; }
> >> >> > }
> >> >> >
> >> >> > ~CMyClass()
> >> >> > {
> >> >> > // Trace.Write( m_guid, m_idStr );
> >> >> > }
> >> >> >
> >> >> > }
> >> >> > private void RunBtn_Click(object sender, System.EventArgs e)
> >> >> > {
> >> >> > ResultEd.Text = "";
> >> >> > try
> >> >> > {
> >> >> >
> >> >> > for( int i = 0; i < int.Parse( NumberEd.Text );> >> >> > ++i )
> >> >> > {
> >> >> >
> >> >> > Hashtable table = new Hashtable( 100 );
> >> >> > ArrayList ids = new ArrayList( 10 );
> >> >> > for( int j = 0; j < 10; ++j )
> >> >> > {
> >> >> > Guid id = Guid.NewGuid();
> >> >> > table[ id ] = null;
> >> >> > ids.Add( id );
> >> >> > }
> >> >> >
> >> >> >
> >> >> > for( int k=0; k < 10; ++k )
> >> >> > {
> >> >> > foreach( Guid id in ids )
> >> >> > {
> >> >> > table[ id ] = new CMyClass( 10 );
> >> >> > }
> >> >> >
> >> >> > CMyClass myobj;
> >> >> > foreach( Guid id in ids )
> >> >> > {
> >> >> > myobj = (CMyClass) table[ id ];
> >> >> > myobj.id.ToString();
> >> >> > }
> >> >> > } // for k
> >> >> > } // for
> >> >> > }
> >> >> > catch( Exception ex )
> >> >> > {
> >> >> > ResultEd.Text = ex.Message + "...CallSTack:" +> >> >> > ex.StackTrace;
> >> >> > }
> >> >> >
> >> >> > GC.Collect();
> >> >> > GC.WaitForPendingFinalizers();
> >> >> > GC.Collect();
> >> >> >
> >> >> > GC.WaitForPendingFinalizers();
> >> >> > GC.Collect();
> >> >> >
> >> >> > ResultEd.Text = "Done";
> >> >> > }
> >> >> >
> >> >> >
> >> >> >
> >> >> >
> >> >
> >> >
> >>
> >>
> >
> >
>
>



Nov 17 '05 #25

P: n/a
That's strange, not too long ago Willy sounded so knowledgable about this
subject and almost like a salesman, now I haven't heard anything from him.
From this I can conclude:

1) Somehow Willy wouldn't dare to admit the truth that GC design and/or
implementation is messed up in this aspect. Hope he's not one of those
"bright" guys that Jon Shemitz referred to as responsible for GC
design/implementation.
2) GC is not releasing unused memory promptly and occasionally it is the
main cause for the process to get shutdown and recycled
2) GC is messing up another one. In the past I also found that that the LOH
(large object heap) gets fragmented gradually and the gap in between each
useful blocks might not ever get to be useful until the whole process gets
recycled (shutdown) because the total amount of used memory reaching max%.
The reason is GC never spends cpu cycles to compact it even before the
process recycles itself.
3) GC.Collect() has no useful purpose other than for decoration (marketing)
because calling it is bad - no one should ever call it, calling it doesn't
do what the name "Collect" suggests anyway. There is no reason for any app
to call it.

"Zeng" <Ze******@hotmail.com> wrote in message
news:ep**************@TK2MSFTNGP11.phx.gbl...
I'm asking you the same question as I have asked BillR:

Is it possible for my process to get recycled because it reaches memory
max% even though most of the memory counted as used is no longer needed by
my app and it is not freed because GC hasn't gotten a chance to do so
safely? If that's true, sounds to me that having a finalizer in my class or not would only *reduce* the chance of that occuring, but not *eliminate*, is that accessment accurate to you?

By the way, I hope I don't need to correct all my mis-understanding what the GC is meant for to raise that question.

"Willy Denoyette [MVP]" <wi*************@telenet.be> wrote in message
news:%2****************@TK2MSFTNGP12.phx.gbl...
Seems like you have a fundamental mis-understanding on what the GC is meant
for and how it's actually performing.
The GC's task is, to collect the memory space occupied by non-reachable
objects and compact the generation it is actually collecting, so that a
contiguous free space remains in the heap to add new objects.
A full GC is a GC run that collects all generations, the current version

of
the CLR has 3 generational logical heaps plus a separate large object heap
(LOH), from code you can ask for a GC run by calling GC.Collect(n) where n indicates the generation to end with, a collection always starts with
generation 0.
GC.Collect() collects all generations plus the LOH, that's why it's called a
full collect.

However, it's NOT the task of the GC to bring down the heap size, that's the
task of the CLR memory manager , or the hosting process memory manager

(if any) in close cooperation with the OS.

Your code sample needs at least two GC.Collect() calls, that's because you have a Finalizer (destructor in C# parlance).
When an instance of a finalizable object gets instantiated, it's

registered
as finalizable.
When it is no longer rooted at the next GC run, it will be moved to the
finalizable queue, where it stays until after the finalizer has run, after which it's removed from the finalizer queue and it becomes eligible for
collection.
Note that it's possible that not all finalizables are immediately

finalized,
all depends on the load of the system and the time the finalizer thread
spends finalizing objects. The finalizer thread can be suspended before

all
finalizer have run, that's why we say at LEAST 2 GC runs, and why we

suggest
against destructors in C#.

Willy.

PS I suggest you start reading these (somewhat outdated) articles , before you start arguing about a subject you don't seem to fully understand.
http://msdn.microsoft.com/msdnmag/is...I/default.aspx
http://msdn.microsoft.com/msdnmag/is...2/default.aspx

"Zeng" <Ze******@hotmail.com> wrote in message
news:eq**************@TK2MSFTNGP14.phx.gbl...
From what I understand, Dispose method doesn't help freeing manage
resources, and that's consistent with what you are saying.

About the hosting process tries to do a full GC run before it recycles
based
on MemoryLimit%; I don't believe it at this point, if there is such

thing as
full GC and it's doing what we expect, then it should have been exposed so
we - developers - can call it when we need to bring down the heap size
immediately (of course we don't need this if full GC is actually possible privately to the framework, but I don't believe it). How many times
should
I try to call GC.Collect to free the dangling objects in my demo code?
And
if GC.Collect doesn't do what "Collect" means, what is its use? Purely
advertising?

Imagine somebody sell you a cabinet and there is knob on it, and he tells you that yes that's a knob but don't use it, you NEVER need or want to use it. If you actually never need to use it then it should be only for
decoration :) but that was only a speculation - and one day you
decide
to pull or turn it, and it doesn't do anything ... hahaha who is more insane, the person tries to use the knob or the person put the knob on the cabinet and didn't think it's for decoration??

"Willy Denoyette [MVP]" <wi*************@telenet.be> wrote in message
news:eA**************@TK2MSFTNGP10.phx.gbl...
> Sorry what I meant was ""there is no documentation ... AND they don't
apply
> here". If you need more info on GC safe points I'm afraid you'll have to> look in the source code files of the CLR if you happen to have a
Source Code
> License. Anyway, when your code calls GC.Collect it's always at a safe
GC> point, it's only when a GC is "induced" that it might get postponed when> your code is not at a GC safe point.
> What Billr proposed makes little sense in your case because your
class don't
> own unmanaged resources, like DB connections, unmanaged memory OS
handles> etc..., it only consumes managed heap memory which is taken care of by> the
> GC, there is no need to force collections by calling GC.Collect yourself.> But if you really think you have to implement IDisposable, go ahead, but> please tell us what you will do in your Dispose method.
>
> I guess I'm more familiar with the process model than you might think.> The
> asp.net hosting process recycles when it's Working Set exceeds the
> memoryLimit% of total available memory, but the hosting process will try to
> survive first by forcing a full GC run, followed by an attempt to reduce the
> working set, then and ONLY when it's WS still exceeds the MemoryLimit% it
> will recycle, else it simply continues to run.
> In case the WS could not be reduced it's simply because an
application> hosted in asp.net allocates too much memory or as a result of heap
> fragmentation (take care when allocating many large objects (>85Kb)),
or as
> a result of a design error.
> When it happens on a production system, it must be considered an
application
> error , because the memoryLimit%, available system memory, number of
active
> clients etc.. should have been defined during staging, when you performed> your load/stress testing and your workload modeling.
>
> Willy.
>
> "Zeng" <Ze******@hotmail.com> wrote in message
> news:%2****************@TK2MSFTNGP09.phx.gbl...
> > I'm not sure on what you mean by "there is no documentation
> > available...because they don't apply here...". The existance of a
> > document
> > doesn't depend on what part of version of my code was posted. I
> > appreciate
> > your help looking into this for me, many people would just ignore posts> > and
> > move on even they know the answer or have some comments, but I don't think
> > we are going anywhere with it. My response was to BillR who proposes that
> > I
> > should be implementing the IDisposable.
> >
> > It's the production environment, if the process get recycled, all my cache
> > in the memory will have to be reloaded when it goes back up. That
> > would
> > cause delay to the service that we want to provide. Sounds like you> > are
> > not
> > familiar with the processModel entry with attribute memoryLimit="60" as
> > default, it's in the machine.config file. thanks!
> >
> >
> > "Willy Denoyette [MVP]" <wi*************@telenet.be> wrote in
message> > news:O5*************@TK2MSFTNGP15.phx.gbl...
> >> Again, you don't have to implement IDisposable when you don't deal
> >> with
> >> managed resources. What do you expect to do in your Dispose method?> >> And
> >> No
> >> there is no documentation available on Safe points, because they
don't> > apply
> >> here (at least not in the code snip you've posted).
> >> I'm also not clear on what you mean with recycling the asp.net
process,
> > is
> >> this something you intend to do or is it something that you are
expecting
> > to
> >> be done automatically, anyway before the asp.net process recycles,> >> all
> >> application domains get unloaded, and this implies a GC run and a
> > finalizer
> >> run, so all objects (still referenced too) will be collected , but
> >> even
> > when
> >> some objects aren't collected, all memory once allocated for the
process
> >> will return to the OS when the process ends. So what are you afraid> >> of?
> >>
> >>
> >> Willy.
> >>
> >> "Zeng" <Ze******@hotmail.com> wrote in message
> >> news:uX**************@tk2msftngp13.phx.gbl...
> >> > Relying on IDisposable won't work easily in the multi-threading
> > scenarios.
> >> > Since the memory required for each object is big, I have put them on
> >> > static
> >> > variable to share it among the servicing threads. Think of CMyClass is
> >> > a
> >> > spell-grammar-checker that helps looking up things and provide
> > suggestions
> >> > for correction for many users create their documents online. In
> >> > this
> >> > scenario, looks like there is the only choice
> >> > --> Make CMyClass disposable and create managing component (internal or
> >> > external to the class) just to coordinate when and which objects are> > done
> >> > just to call Dispose. This sounds like the intensive plumbing
and> >> > error-prone approach that I was so used to with C++
> >> >
> >> > Conceptually, this is the drawback of a smart system, the
programmer> > knows
> >> > what he/she needs to be done but can't change its behavior (which is
> > very
> >> > very smart most of the time)
> >> >
> >> > By the way, where can I find a documentation about the safe-points?> >> > Wouldn't that be better that there is a call to wait for the system to
> > be
> >> > done with collection and there is a safe point in that method?
And> >> > is
> >> > there
> >> > a safe point in the component that checks for memory usage and
recycle
> > the
> >> > aspnet process when 60%(default) is reached?
> >> >
> >> >
> >> >
> >> > "billr" <bi***@discussions.microsoft.com> wrote in message
> >> > news:3B**********************************@microsof t.com...
> >> >> and just to add my two pennies worth ...
> >> >>
> >> >> Although you may call GC.Collect(), much the same as in Java when you
> > try
> >> > to
> >> >> force the VM to run garbage collection, it will still run at it's> >> >> earliest
> >> >> convenience.
> >> >>
> >> >> During compilation, your code is injected with "safe points"
> >> >> whereby
> > the
> >> > GC
> >> >> can hijack the thread and take control to do its work. Now, when> >> >> you
> > call
> >> >> GC.Collect() your code might not be in a stable enough state for> >> >> the
> >> >> GC
> >> >> to
> >> >> run, and the only way that the GC can know that it is safe to run> >> >> is
> >> >> if
> >> >> it
> >> >> has reached a "safe point".
> >> >>
> >> >> Generally speaking, it is bad practice to call GC.Collect() since you
> >> >> will
> >> >> inadvertantly interrupt a perfectly (or near to) working system,> >> >> and
> > you
> >> >> yourself can cause all sorts of naughtiness to occur.
> >> >>
> >> >> My choice of preference (as it is for a lot of developers) is to> >> >> implement
> >> >> IDisposable.
> >> >>
> >> >> AND, yes, our code should be easily readable and left in a state that
> >> >> renders it possible for future devlopers to look at it and see

what is
> >> > going
> >> >> on (for maintenance reasons, or whatever), however, designing our> > classes
> >> >> "off centre" just in case, the next developer doesn't know as much as
> > us
> >> > is a
> >> >> pretty poor choice IMHO.
> >> >>
> >> >> --
> >> >> Of all words of tongue and pen, the saddest are: "It might have
been"
> >> >>
> >> >> Bill.Richards @ greyskin .co .uk
> >> >> http://greyskin.co.uk
> >> >>
> >> >>
> >> >> "Zeng" wrote:
> >> >>
> >> >> >
> >> >> > I finally narrowed down my code to this situation, quite a few (not
> >> >> > all)
> >> > of
> >> >> > my CMyClass objects got hold up after each run of this function via
> > the
> >> >> > simple webpage that shows NumberEd editbox. My memory profile shows
> >> > that
> >> >> > those instances survive 3 rounds of GC collections - it's not
> >> >> > what
I
> >> >> > expected. In my real code, CMyClass occupies big amount of
> >> >> > memory
> > and
> >> > they
> >> >> > all share one stance of another class that I don't have enough> >> >> > memory
> >> > hold
> >> >> > more than a just a few in the memory. Notice that the
> >> >> > finalizaer
> > the
> >> > my
> >> >> > CMyClass makes a big difference in demonstrating this issue, w/o it
> > the
> >> >> > problem doesn't exist. The interesting thing is if I run the
> >> >> > page
> >> > again,
> >> >> > the old dangling ones got destroyed and the new ones become
> >> >> > dangling.
> >> >> > Am
> >> > I
> >> >> > missing something about the GC? Do I need to explicitly implement> >> >> > and
> >> > call
> >> >> > dispose for these classes instead of relying on GC to promptly> > collect
> >> > it?
> >> >> > Apparently somehow these objects can survive the automatic
> >> >> > collections...disposing it would help. Thanks for your comment> >> >> > and
> >> >> > help.
> >> >> >
> >> >> > internal class CMyClass
> >> >> > {
> >> >> > ArrayList m_array = new ArrayList( 50000 );
> >> >> > private string m_idStr;
> >> >> > private Guid m_guid;
> >> >> > internal CMyClass( int n )
> >> >> > {
> >> >> > for( int i = 0; i < n; ++i )
> >> >> > m_array.Add( Guid.NewGuid() );
> >> >> >
> >> >> > m_guid = Guid.NewGuid();
> >> >> > m_idStr = m_guid.ToString();
> >> >> > }
> >> >> >
> >> >> > internal Guid id
> >> >> > {
> >> >> > get{ return (Guid ) m_array[ 0 ]; }
> >> >> > }
> >> >> >
> >> >> > ~CMyClass()
> >> >> > {
> >> >> > // Trace.Write( m_guid, m_idStr );
> >> >> > }
> >> >> >
> >> >> > }
> >> >> > private void RunBtn_Click(object sender, System.EventArgs e)
> >> >> > {
> >> >> > ResultEd.Text = "";
> >> >> > try
> >> >> > {
> >> >> >
> >> >> > for( int i = 0; i < int.Parse( NumberEd.Text );> >> >> > ++i )
> >> >> > {
> >> >> >
> >> >> > Hashtable table = new Hashtable( 100 );
> >> >> > ArrayList ids = new ArrayList( 10 );
> >> >> > for( int j = 0; j < 10; ++j )
> >> >> > {
> >> >> > Guid id = Guid.NewGuid();
> >> >> > table[ id ] = null;
> >> >> > ids.Add( id );
> >> >> > }
> >> >> >
> >> >> >
> >> >> > for( int k=0; k < 10; ++k )
> >> >> > {
> >> >> > foreach( Guid id in ids )
> >> >> > {
> >> >> > table[ id ] = new CMyClass( 10 );
> >> >> > }
> >> >> >
> >> >> > CMyClass myobj;
> >> >> > foreach( Guid id in ids )
> >> >> > {
> >> >> > myobj = (CMyClass) table[ id ];
> >> >> > myobj.id.ToString();
> >> >> > }
> >> >> > } // for k
> >> >> > } // for
> >> >> > }
> >> >> > catch( Exception ex )
> >> >> > {
> >> >> > ResultEd.Text = ex.Message + "...CallSTack:" +> >> >> > ex.StackTrace;
> >> >> > }
> >> >> >
> >> >> > GC.Collect();
> >> >> > GC.WaitForPendingFinalizers();
> >> >> > GC.Collect();
> >> >> >
> >> >> > GC.WaitForPendingFinalizers();
> >> >> > GC.Collect();
> >> >> >
> >> >> > ResultEd.Text = "Done";
> >> >> > }
> >> >> >
> >> >> >
> >> >> >
> >> >> >
> >> >
> >> >
> >>
> >>
> >
> >
>
>



Nov 17 '05 #26

This discussion thread is closed

Replies have been disabled for this discussion.