|
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;
|
|
|
|
|
OK, lets assume I collected 101 in base 2 into num1 and 75 in base 8 into num2
How do I write the code for the conversion, adding the two numbers and put the result in a base from the user (say $base_result)
|
|
|
|
|
I have told you how to do it and what methods to use for it. Can't you at least make an attempt at writing some code yourself, before asking?
---
single minded; short sighted; long gone;
|
|
|
|
|
Thanks for the info, however I'm not sure how to do it.
I looked at MSDN and tried to learn from there but still couldn't understand how to do it.
I wouldn't come to the forum if I knew
|
|
|
|
|