|
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.
|
|
|
|
|
Hello,
i cant'n connect to my sql server
its' error is:
!qlexception was unhandled
Login failed for user 'sa'. Reason: Not associated with a trusted SQL Server connection.
my code is this:
SqlConnection objConnection = new SqlConnection(
"server=localhost;database=pubs;"+"user id=sa;password=");
that error happened here:
objConnection.Open();
can you help me?
Thank you very much.
H.Jafari
|
|
|
|
|
This question would probably be better in the SQL forum
But in answer to your question:
when you installed Sql Server and it asked about authentication did you leave it as Windows Authentication or change it to Mixed Mode?
If it's set to Windows Authentication then you can't use sql logins.
|
|
|
|
|
No You have a error in Connection String pls modify ur Connection String like that:
SqlConnection objConnection = new SqlConnection(
"server=localhost;database=pubs;uid=sa;password=if any");
Regards,
Karthick
Iam Karthick from Chennai Dot Net Developer
|
|
|
|
|
"User ID" is a valid property to have in the connection string, and the concatonation shouldn't cause any issue either.
http://www.connectionstrings.com/[^]
Which part did you think was incorrect?
-- modified at 9:34 Monday 30th July, 2007
Opps that didn't sound quite how I ment it. What I ment to say was:
Is there something wrong that I missed?
|
|
|
|
|
Hi!
I working on a Pocket PC Device application and i need help
How to verify if another instance of my program is already running? And if another instance is already running I want to make the one already open to get focus.
Please hep me!
Thank you
--------------------------------
visit: http://pmartike.deviantart.com/
|
|
|
|
|
Hello,
Look at System.Diagnostics.Process!
There you will find "GetProcessByName".
Look also at this answere I gave some time ago:
MainWindowHandle[^]
All the best,
Martin
|
|
|
|
|
I am writing following code for impersonation but it doens work.
Can anybody tell me why?
serverConn = new ServerConnection();
serverConn.LoginSecure = true;
serverConn.ConnectAsUser = true;
serverConn.ConnectAsUserName = userName + "@" + userDomain;
serverConn.ConnectAsUserPassword = userPassword;
This connection is used tofr creating database.
Please help
Nana
|
|
|
|
|
hi
Sir,
I have created a Sample Application where a fonts file is referenced from
C:\WINDOWS\Fonts
my requirment is in that my Sample Application should not
use from C:\WINDOWS\Fonts\*.tff path
it use the fonts file *.tff from SampleApplication.resx file
so that my SampleApplication can get fonts irrespective of
font installation in C:\WINDOWS\Fonts
thank u
Fly Like An Eagle With MIGHTY POWER.
|
|
|
|
|
I would appreciate if someone here can help me with the following:
I need to write a small program in C# that does the following:
1. Collect from a user 2 numbers (different bases - Bin, Oct, Dec or Hex) and store them in integer
2. Then collect the operator from the user (+, -, *, /)
3. Then collect in what base the result will be presented (Bin, Oct, Dec or Hex)
4. And then print the result
No graphics is required here. Something to run from the command line.
I know it is simple but could not figure how to do it,
I would appreciate your help here,
Thanks,
Dana.
|
|
|
|
|
So where are you stuck exactly? We won't write the entire code for you.
regards
modified 12-Sep-18 21:01pm.
|
|
|
|
|
How do I take the 2 numbers from different bases, do the addition for example and present it in a different base?
|
|
|
|
|
guyav99 wrote: How do I take the 2 numbers
Console.ReadLine
guyav99 wrote: from different bases
Depends on how you represent them. You can use string parsing methods or int.Parse()
guyav99 wrote: do the addition for example
Convert them to the same base and use +
guyav99 wrote: and present it in a different base?
number.ToString() with a format specifiert should do the trick
modified 12-Sep-18 21:01pm.
|
|
|
|
|
Parse the strings into numbers using the selected base, do the addition, and convert the numbers into strings useing the selected base.
The Convert.ToInt32 and Convert.ToString methods have overloads that handle different bases.
---
single minded; short sighted; long gone;
|
|
|
|
|