|
Help me to get the memory details as u retrieve the hardware info.
If possible send the code
|
|
|
|
|
You can retirve hardware configuration information via WMI[^].
Here's some info on how to access it from C#:
C# WMI[^].
|
|
|
|
|
What is the use of having Dispose() method in class. All .NET classes are under managed code and garbage collection will be done automatically. But some classes like Dataset having dispose method. When we need to use dispose method for our class ? Writing dispose method for all classes is a good practice ?
|
|
|
|
|
Hello,
I often implement "IDisposable" with the Dispose method to unregister delegates to manager classes (classes which are allways in memory in my app) there.
All the best,
Martin
|
|
|
|
|
Thanks you. So if the code is 100% managed, do we need to implement this ?
|
|
|
|
|
|
AS A USER...
You should call Dispose() if that is the only way to clean up, as is typically the
case when unmanaged resources are involved.
You should call Dispose() if the class offers that method, since you don't know
whether it is using unmanaged resources; example OpenFileDialog()
For Framework classes you should read MSDN, and pay attention to the remarks it
contains regarding Dispose(), Close() and the like.
BTW: In C# the best way to call Dispose() often is with a using construct.
AS A PROVIDER...
You should do the reciprocal, including:
You should implement IDisposable if your object is likely to hold large amounts of
(managed) memory that you want to make collectable immediately, or some resources
you want to free immediately (e.g. an open file).
If your class has a Dispose() you should clarify its use in your documentation.
|
|
|
|
|
Luc Pattyn wrote: You should implement IDisposable if your object is likely to hold large amounts of
(managed) memory that you want to make collectable immediately
Actually, there is rarely any reason to try to release memory earlier. You might even end up holding on to the memory longer than if you didn't try to release it.
Example:
ObjectWithHugeArray obj = new ObjectWithHugeArray();
obj.GetSomeData();
obj.DisplayTheData();
GetSomeUserInput();
obj.Dispose();
obj = null;
ObjectWithHugeArray obj = new ObjectWithHugeArray();
obj.GetSomeData();
obj.DisplayTheData();
GetSomeUserInput();
obj = null;
(Yes, the example is a bit silly, but it tries to show that sometimes the garbage collector is smarter than the programmer...)
---
single minded; short sighted; long gone;
|
|
|
|
|
Hi Guffa,
Guffa wrote: ObjectWithHugeArray obj = new ObjectWithHugeArray();
obj.GetSomeData();obj.DisplayTheData();
// the memory is collectable here already
GetSomeUserInput();
obj = null;
I think I don't agree in general and with the // comment in particular.
I assume you intend the example to be the code of a single method, with obj
a class member, not a local variable.
(if it were a local variable, setting it to null with no statements following
that use it's value, the "obj=null;" statement would be chopped out
by the optimizer).
Not having an obj.Dispose(); ends the life of the obj value sooner when
looking at the code in the method itself; IMO that on its own is insufficient to
expect the compiler to move "obj=null;" upwards. And it is not allowed to move
it over the GetSomeUserInput() method call, without making sure the value of obj
isnt used in there.
So I expect the obj variable be present on the stack, and be cleared only
after returning from the Input method; hence the GC would find the hugeobject
reference, and would have to keep it alive (together with its huge array, for
which my Dispose() would have removed the only reference).
So I don't see how your example works in substatntiating your statement
that Dispose() could work adversely, which I still don't see possible.
|
|
|
|
|
Hello Luc,
Luc Pattyn wrote: with obj
a class member, not a local variable.
But the example looks like it is a local vatiable, doesn't it?
"ObjectWithHugeArray obj = new ObjectWithHugeArray();"
Luc Pattyn wrote: the "obj=null;" statement would be chopped out
by the optimizer
Really!
I use it very often, because I thought it is recomended behaviour, to help the GC.
I think there was a discussion in the past about that, let me look!
-- modified at 11:28 Monday 30th July, 2007
Found it, Scott Dorman gave me that information[^] some time ago.
All the best,
Martin
|
|
|
|
|
Hi Martin,
it will require more investigation; seems the C#2005 compiler is dumber than
I expected (I don't know what the JIT does to it).
Even in release mode, it keeps both "ref=null;" and "val=12;" statements,
even as the last line of a method and for local vars.
For value types that does not make sense at all.
For ref types it could make sense (to throw away the reference, so the object
may become collectable); here the compiler may be keeping it on purpose in
general, but keeping it for a local ref on the last line does not make any sense.
Whatever the compiler does to it, it makes sense (and I apply it too) to
nullify a ref that is a class member everywhere in your code, and I guess
they have (and should have) done something special so you could nullify a local ref
anywhere in a method to throw the ref away earlier than method exit.
I will tell when and if I have more on this.
|
|
|
|
|
Hi Martin,
I investigated the GC stuff somewhat deeper, see here[^]
Net result is: ptr=null; makes sense, the compiler uses a "ldnull stloc" instruction sequence, which the JIT will not move or optimize away.
Luc Pattyn [Forum Guidelines] [My Articles]
this weeks tips:
- make Visual display line numbers: Tools/Options/TextEditor/...
- show exceptions with ToString() to see all information
- before you ask a question here, search CodeProject, then Google
|
|
|
|
|
Hello Luc,
Very interesting!!! (Got my five)
Thank you for taking time!
I followed this thread every day (have it in my Favorites), because it was interesting for me.
I was a little surpriesed that the disussion between you and Guffa ran in a "wrong" (abuse) direction.
Hope it doesn't change your behavioure her on CP.
Go on with the good work!!!
Thanks again!
All the best,
Martin
|
|
|
|
|
Luc Pattyn wrote: I assume you intend the example to be the code of a single method, with obj
a class member, not a local variable.
Assume away.
It's a local variable.
Luc Pattyn wrote: Not having an obj.Dispose(); ends the life of the obj value sooner when
looking at the code in the method itself; IMO that on its own is insufficient to
expect the compiler to move "obj=null;" upwards.
The compiler will not move the "obj=null;", and it doesn't have to. That statement is irrelevant for the live time of the reference to the object, as it doesn't use the reference, it only assigns a new value to the reference variable. The last use of the reference is where it's read, not where it's written.
Luc Pattyn wrote: So I expect the obj variable be present on the stack, and be cleared only
after returning from the Input method; hence the GC would find the hugeobject
reference, and would have to keep it alive (together with its huge array, for
which my Dispose() would have removed the only reference).
No, the object only have to be alive as long as there is a used reference to it. The garbage collector sees where the reference to the object is last used, and can collect the object before the input method. If you have a Dispose call, the object has to be kept alive until then.
---
single minded; short sighted; long gone;
|
|
|
|
|
Hi Guffa,
you're not convincing me at all.
Guffa wrote: the object only have to be alive as long as there is a used reference to it. The garbage collector sees where the reference to the object is last used
You assign magic powers to the GC; it does not understand your program, it can't
predict whether an existing reference is still needed or not.
This is a first approximation on how a GC basically works: the only thing the GC
sees is a process with a bunch of threads; each thread has a stack and its copy
of the CPU's registers. When the GC wants to get an updated view on things,
it suspends all threads in the process, then deals with each thread in turn.
Inside each stack and register set, it scans for references, to build one big
list of things it can see; afterwards it loops over all existing objects (they
all are in a linked list), and removes the ones that don't appear in the
list of reachable objects.
The local ref-type variable is located on the stack (or JIT-optimized into a
register). If it is not null, the object it refers to is alive, even if the
program does not intend to use it any more. That's exactly why it may be wise
to assign null to it.
Now my problem was: why would the compiler actually generate code to assign
null to it, since there is no further use for it; a regular non-CLR compiler
(say a C compiler) would optimize it away immediately. But it seems the C# compiler
designer has not optimized assignments that far that "obj=null;" would be
removed. (Unfortunately he also did not remove useless val-type assignments,
try ending a method on int a=12; and watch its MSIL).
So I still believe "obj=null;" is useful if obj is not a local variable,
as well as for a local variable that half-way the method is no longer needed.
If you don't assign null to the local variable, it will survive until it gets
removed from the stack by returning from the method; with a null assignment,
it disappears earlier (but does not necessarily gets collected immediately),
and with a Dispose() you are sure whatever unmanaged resources it holds get
released immediately, without changing the point in time the object itself
becomes unreachable, hence collectable.
|
|
|
|
|
Luc Pattyn wrote: You assign magic powers to the GC; it does not understand your program
Yes, it does. All it has to do is to check where the variables are used. That's not very complicated.
Luc Pattyn wrote: it can't
predict whether an existing reference is still needed or not.
Yes, it can, and it does.
Luc Pattyn wrote: The local ref-type variable is located on the stack (or JIT-optimized into a
register). If it is not null, the object it refers to is alive, even if the
program does not intend to use it any more.
That's not accurate. The object is only alive as long as the reference to it is used. When the garbage collector knows that the referens is not going to be used any more, the reference is no longer considered, and the object is no longer alive.
This can easily be demonstrated with this program:
using System;
using System.Collections.Generic;
namespace TestConsole {
class Program {
static List<WeakReference> refs;
static void Main(string[] args) {
refs = new List<WeakReference>();
byte[] ref1, ref2, ref3, ref4, ref5, ref6, ref7, ref8, ref9, ref10;
ref1 = Create();
ref2 = Create();
ref3 = Create();
ref4 = Create();
ref5 = Create();
ref6 = Create();
ref7 = Create();
ref8 = Create();
ref9 = Create();
ref10 = Create();
int index = 1;
foreach (WeakReference r in refs) {
Console.WriteLine("Item {0} : {1}", index, r.IsAlive);
}
}
static byte[] Create() {
byte[] r = new byte[100000000];
refs.Add(new WeakReference(r));
return r;
}
}
}
When you run it, it will show that only one (at least on my system) of the arrays is still alive. The others have been garbage collected, despite there being specific references to them.
If you try it, be sure to run it in release mode. In debug mode the references are considered active for their entire scope, so that the debugger can show their values.
Luc Pattyn wrote: Now my problem was: why would the compiler actually generate code to assign
null to it, since there is no further use for it; a regular non-CLR compiler
(say a C compiler) would optimize it away immediately. But it seems the C# compiler
designer has not optimized assignments that far that "obj=null;" would be
removed. (Unfortunately he also did not remove useless val-type assignments,
try ending a method on int a=12; and watch its MSIL).
The compiler doesn't do much optimising. Almost all optimising is done by the JIT compiler, so you should look at the actual code generated, not the IL code.
---
single minded; short sighted; long gone;
|
|
|
|
|
Hi Guffa,
we are not converging yet !
The GC is not looking at code. There is no point in trying to figure
out what each of the threads in a program is going to do in the future.
How would the GC deal with changes in program flow, loops, recursive methods,
etc etc? It is just impossible.
All the GC looks at is reachable data, everything it can reach (in the
way I explained before) is considered alive and will not be collected.
I must add one refinement, the one your latest example is abusing
(I did not run your example, I understood what you meant with it): the GC
does not follow weak references when looking for reachable objects. Hence,
if an object is only reachable through one or more weak references, but not
a single normal reference, it does not get marked as reachable, and hence:
- it is collectable
- it does not contribute to any more reachables (by the references it may be holding)
BTW: I have seen the actual code of several non-Microsoft GC implementations,
and read dozens of articles on it (also Microsoft's); so I am pretty sure about
the theory behind them; I also have no indication whatsoever that the GC in .NET
is completely different from all the others.
Guffa wrote: Almost all optimising is done by the JIT compiler, so you should look at the actual code generated, not the IL code.
I would like to do that, have not done that so far. Two problems:
1. can you tell me the easiest way to do that (find the code, then watch it;
I am quite familiar with Intel assembly, I even write some occasionally,
and I used to watch it in VS 6, that's before .NET)
2. I am afraid it is more volatile now, the code may be different on different
runs due to whatever circumstances it takes into account; so it might be harder
to draw valid conclusions from it.
Greetings
|
|
|
|
|
Luc Pattyn wrote: The GC is not looking at code.
Yes, it is.
Luc Pattyn wrote: There is no point in trying to figure
out what each of the threads in a program is going to do in the future.
How would the GC deal with changes in program flow, loops, recursive methods,
etc etc? It is just impossible.
The GC doesn't deal with changes in program flow. It only deals with the possible program flows. If the code possibly can use a variable, it's of course considered to be used.
Luc Pattyn wrote: All the GC looks at is reachable data, everything it can reach (in the
way I explained before) is considered alive and will not be collected.
No, it looks at used data. Everything that used references can reach is alive. I just proved with the program in my previous post that it collects data that still has references to it.
Luc Pattyn wrote: I must add one refinement, the one your latest example is abusing
(I did not run your example, I understood what you meant with it): the GC
does not follow weak references when looking for reachable objects.
You obviously did not understand my example. The weak references are only used to monitor the objects, there are specific references (ref1, ref2, et.c.) to each of the objects. Take another look at it.
Luc Pattyn wrote: can you tell me the easiest way to do that (find the code, then watch it;
Start debugging and open the disassembly window (Alt+Ctrl+D).
---
single minded; short sighted; long gone;
|
|
|
|
|
Hi Guffa,
here is, I think, the verdict on our GC disagreement:
BTW: I was unable to see disassembly, CTRL/ALT/D is not available in C# Express Edition
(it is in C# Pro, and in all C++ tho). See "How to: Use the Disassembly Window"
on MSDN.
Any suggestion (except the obvious) is welcome.
I studied your program in detail;
in debug, it keeps all the arrays (but not on purpose, as you implied; but rather
because the MSIL did not get optimized, as we will see later)
in release, it throws away everything immediately
The big difference between the two is apparent in the MSIL:
debug generates a call to Create(), then an stloc to save the pointer in a local
(there are 4 numbered ones, the rest is on stack);
in my theory the GC sees these pointers till the method Main() is done.
release generates same call, then a pop, since the arrays are never used,
there is no need to keep the pointers; hence the GC in my theory never sees the arrays.
So I came up with a slightly different test program.
It has two test cases, one very similar to yours,
one more realistic in that the arrays are really used within the method,
so they get stored.
I used smaller arrays but included explicit GC calls, and one explicit ptr=null statement.
Results:
- debug test case 1 keeps everything alive
- release test case 1 does not store a single pointer, so everything is gone
- test case 2 behaves identical in debug and release, it acts according to my
theory: objects get collected if they have no references on stack, either because
the stack unwinds (end of method), or they get nulled.
So I maintain GC does not look at code, it scans the stacks.
And nulling a reference is useful if:
- the ref is somehow global;
- or the ref is local but followed by more code (hence no stack unwinding imminent)
class Program {
static List<WeakReference> refs;
static void Main(string[] args) {
Console.WriteLine("===========================================");
withoutConsumers();
Console.WriteLine("===========================================");
withConsumers();
Console.WriteLine("===========================================");
Console.WriteLine("Hit ENTER to terminate");
Console.ReadLine();
}
static void withoutConsumers() {
Console.WriteLine("Arrays are created but never really used");
refs = new List<WeakReference>();
byte[] ref1, ref2, ref3;
ref1 = Create_1MB();
ref2 = Create_1MB();
ref3 = Create_1MB();
Show("after creates");
Collect();
Show("after collect");
ref2=null;
Show("after cref2=null");
Collect();
Show("after collect");
}
static void withConsumers() {
Console.WriteLine("This time arrays are really used");
refs = new List<WeakReference>();
byte[] ref1, ref2, ref3;
ref1 = Create_1MB();
ref2 = Create_1MB();
ref3 = Create_1MB();
Show("after creates");
int n=ref1[1]+ref2[2]+ref3[3];
Console.WriteLine("n="+n);
Collect();
Show("after collect");
ref2=null;
Show("after cref2=null");
Collect();
Show("after collect");
}
static byte[] Create_1MB() {
byte[] r = new byte[1024*1024];
for(int i=0; i<100; i++) r[i]=(byte)i;
refs.Add(new WeakReference(r));
return r;
}
static void Show(string title) {
string s=title.PadRight(20);
foreach(WeakReference r in refs) s+=" "+r.IsAlive;
Console.WriteLine(s);
}
static void Collect() {
GC.Collect();
GC.Collect();
GC.Collect();
}
}
This is the output it generates in debug mode:
Arrays are created but never really used
after creates True True True
after collect True True True
after cref2=null True True True
after collect True False True
===========================================
This time arrays are really used
after creates True True True
n=6
after collect True True True
after cref2=null True True True
after collect True False True
This is the output it generates in release mode:
Arrays are created but never really used
after creates False False True
after collect False False False
after cref2=null False False False
after collect False False False
===========================================
This time arrays are really used
after creates True True True
n=6
after collect True True True
after cref2=null True True True
after collect True False True
Hope this convincingly illustrates my theory.
[Added: my interest in this got triggered by the idea that ptr=null; without
further consumers for ptr should and would be optimized away by a good compiler;
turns out that MSIL has a ldc.i4.0 to load a 4-byte integer zero, and
a ldnull instruction to push a null reference.
So from this the JIT knows it could eliminate a "ldc.i4.0 stloc" sequence
if the target of the stloc is not alive (life analysis by JIT, not by GC),
but more importantly it will have a built-in rule preventing it from
eliminating the sequence "ldnull stloc". So my mystery is solved.]
-- modified at 20:55 Saturday 4th August, 2007
|
|
|
|
|
Hi Guffa,
here is a code snippet that should convince you a GC can not possibly predict
the future, i.e. it can not predict whether an object that is still reachable
(according to my definition) will still be used, no matter how hard it
investigates the code:
public static void GCCantPredictCodeExecution() {
object doYouStillNeedMe = new object();
Thread.Sleep(1000);
Console.WriteLine("Type 1 to show the object, 0 to skip that");
string s=Console.ReadLine();
if (s=="1") Console.WriteLine(doYouStillNeedMe.ToString());
#if withNullify
doYouStillNeedMe=null;
#endif
Thread.Sleep(1000);
}
So, assuming GC runs at least once a second (if necessary, add GC.Collect()
statements!), when will object doYouStillNeedMe become collectable ?
My answer is:
- D if withNullify is defined since now the ref is no longer on stack
- E if withNullify is undefined, since that's when the stack unwinds to the caller
And if I understood you correctly, you would say A or C depending on what will
be input ???
|
|
|
|
|
Of course the GC doesn't predict the future. It's a bit silly of you to even suggest that I said something like that.
The GC only examines the code, not the data, so any input from the user is irrelevant for the analysis.
The object will always be collectable at point C (unless run in debug mode). Writing a new value to the reference variable does not read the value in the variable, so the GC knows already at point C that the object reference will not be used anymore. When you write the null value to the reference variable, the reference to the object is already unused.
---
single minded; short sighted; long gone;
|
|
|
|
|
|
Even though you may be using only managed code, many of the base classes in .NET use the Win32 API and other unmanaged code internally. The Dispose method is used by the GC to know how to clean up that unmanaged memory.
As far as using (calling) Dispose , it can be safely assumed to be a best practice that if the class implements Dispose (or the IDisposable interface, then you should call the Dispose method when you are done using the class. This is most easily accomplished by the using statement, which defines a scope, outside of which an object or objects will be disposed.
using (Font font1 = new Font("Arial", 10.0f)) If you are writing your own classes, you want to implement IDisposable if
1. you have unmanaged resources that you are working with internally
2. any class in your inheritance chain implements IDisposable
3. you want to explicitly manage the lifetime of the class
You can check out the following references for more information:
Implementing IDisposable and the Dispose Pattern Properly[^]
Using Garbage Collection in .NET[^]
|
|
|
|
|
Thank you. it was really worth reading. Thank you very much
|
|
|
|
|
You're welcome. Glad it helped.
|
|
|
|
|