From: Daniel Lidstrom on 24 Jun 2010 06:05 "Andrew Baker" <ajb_news(a)anmel.co.uk> wrote in message news:4c231fe8$0$12167$fa0fcedb(a)news.zen.co.uk... > Because the timer is active (enabled), there's still a live reference to > it, preventing the garbage collection. You've not got direct access to > this reference, 'the system' has got one inside the workings of the .net > framework somewhere. Ah yes, that would explain it. Thanks for the insight Andrew. Daniel
From: Adam Clauss on 24 Jun 2010 09:31 On 6/24/2010 4:05 AM, Andrew Baker wrote: > Because the timer is active (enabled), there's still a live reference > to it, preventing the garbage collection. You've not got direct access > to this reference, 'the system' has got one inside the workings of the > .net framework somewhere. I'm not sure that's accurate - I'm pretty sure I've seen cases where I created and enabled a timer, forget to stash away a reference to it, and the timer would fire once or twice - and then nothing. I assumed it had gotten garbage collected. -Adam
From: Peter Duniho on 24 Jun 2010 11:00 Adam Clauss wrote: > On 6/24/2010 4:05 AM, Andrew Baker wrote: >> Because the timer is active (enabled), there's still a live reference >> to it, preventing the garbage collection. You've not got direct access >> to this reference, 'the system' has got one inside the workings of the >> .net framework somewhere. > > I'm not sure that's accurate - I'm pretty sure I've seen cases where I > created and enabled a timer, forget to stash away a reference to it, and > the timer would fire once or twice - and then nothing. I assumed it had > gotten garbage collected. It depends on which Timer class you are using. There are three primary Timer classes found in .NET. The System.Threading.Timer and System.Timers.Timer classes require that the client code retain a reference, otherwise the object will be GC'ed. But my recollection is that System.Windows.Forms.Timer should continue to work even without an explicit reference, for the reason Andrew mentions. So, then the question becomes why the object isn't collected in Daniel's sample code, since he's using one of the Timer classes that is subject to GC. The answer to that is most likely because he's running a "Debug" version of the program. The secondary code block within his Main() method doesn't affect object lifetime. References are managed at the method level. But the optimization of releasing variables within a method after their last use happens only in "Release" builds (i.e. optimized builds). I don't have time to test it right now, but I suspect that the original code will do what Daniel expects if it's compiled with optimizations (i.e. as "Release"). Pete
From: Peter Duniho on 24 Jun 2010 11:07 Mr. Arnold wrote: > Daniel Lidstrom wrote: >> "Mr. Arnold" <Arnold(a)Arnold.com> wrote in message >> news:enGFmQ3ELHA.1316(a)TK2MSFTNGP02.phx.gbl... >>> >>> I guess you can just set the Timer to null Timer=null that should >>> kill it. >> >> Neither setting timer nor timerTest to null helped in this case. Even >> if it had helped I think that in a larger >> application it becomes impractical to have to set unused references to >> null. > > I guess you have never worked in the COM, DCOM or COM+ environment, back > in the day for large applications, where objects had to be set manually > to null to release resources. These technologies are still being used to > this day. That makes no sense. You don't set objects to null, you set variables to null. And setting variables to null only has an effect on object lifetime in GC'ed environments like .NET. In unmanaged code, setting a variable that references a COM object to null has no effect on the lifetime of that object whatsoever. In fact, a major problem when writing COM code is failing to explicitly call the Release() method exactly the right number of times to offset each "reference count" that was added to the object, to ensure that the object is in fact released and the memory freed. Getting those reference counts and calls to Release() balanced is a major pain in the neck and is why a GC system like what .NET uses is such a boon: specifically because in .NET, setting a variable reference to null _is_ sufficient to release the object (eventually). Using COM, it's entirely possible to have an object that is no longer reachable � that is, no variable references the object directly or indirectly � and yet which is still allocated. Being unreachable, there would be no way to _ever_ free the object. In .NET, by definition an object that is unreachable can and will eventually be freed. Pete
From: David Boucherie & Co on 26 Jun 2010 15:07 This is a bit simplified, but in essence, the garbage collector works as follows... First off, the garbage collector runs whenever: � Physical memory is low. � The memory that is used by allocated objects (on the managed heap) surpasses a certain threshold (which is dynamically calculated while running). � GC.Collect() is called (the method you use in your code). Allocated objects (in the managed heap) get a generation: � 0: very-short lived objects (like temporary variables). � 1: short-lived objects � 2: long-lived objects Garbage collection is run on a specific generation depending on certain conditions. All objects of that generation or lower are then collected. (A generation 2 garbage collection is also known as a full garbage collection.) Objects that "survive" a collection pass are promoted to the next generation. So when a generation 0 garbage collection occurs, any object not collected becomes generation 1, 1 becomes 2, and 2 remains 2. A full garbage collection has three phases: � Live objects are marked, dead objects become "condemned". � References to objects that will be compacted (moved together, simply put) are updated. � Space occupied by dead objects is reclaimed and surviving objects are compacted. However, dead objects that have finalizers are not reclaimed, but marked as finalize pending. Also, all references in the finalizers cause the objects referenced to be kept alive too, even if they would otherwise be condemned! A finalization thread is started after collection is complete and starts executing all pending finalizers, causing the finalized objects to become dead again. However, they are not collected until the garbage collector makes its next run. On top of that, full garbage collection is expensive in time and CPU power, so usually garbage collection is only partial and works only on lower generation objects. In short: when you run your garbage collector, there is no way to be sure that a certain object will be effectively destroyed at any one time, nor can you exactly predict when finalizers will be run. To force a full garbage collection (generation 2), use: GC.Collect(2, GCCollectionMode.Forced ); Now that I have explained all that... I have NO CLUE why your timer doesn't get killed. :P It doesn't even finalize after disposing it, even when forcing a full garbage collection! The finalizer only runs when the program ends (after ReadLine()). I suppose some hidden references exist... but I don't see where. I even tried with a simple class, replacing your timer with an int instead, and still no joy. Anyone can explain it? Because I can't! On a side note: Your code contains a resource leak. Your Timer will eventually be collected, but as you don't Dispose() it, it will keep its system resources located. I changed your code a bit, and to my astonishment, the Timer isn't collected... using System; using System.Timers; namespace ConsoleApplication1 { public class TimerTest : IDisposable { Timer timer; public TimerTest() { timer = new Timer( 1000 ); timer.Elapsed += ( o, e ) => { Console.WriteLine( "Timer elapsed " + e.SignalTime.ToLocalTime() ); }; timer.Start(); } ~TimerTest() { Console.WriteLine( "Finalizing!" ); } public static void Main() { { TimerTest timerTest = new TimerTest(); timerTest.Dispose(); } Console.WriteLine( "Collection 1." ); GC.Collect( 2, GCCollectionMode.Forced ); Console.WriteLine( "Suspending thread waiting for finalizers." ); GC.WaitForPendingFinalizers(); Console.WriteLine( "Collection 2." ); GC.Collect( 2, GCCollectionMode.Forced ); Console.ReadLine(); } #region IDisposable Members public void Dispose() { Console.WriteLine( "Disposing timer." ); timer.Dispose(); } #endregion } } Daniel Lidstrom wrote: > Hello, > > I am trying to understand how the garbage collector works. To do this I > created a simple test with a timer. I create a timer and then release > all references leading to this timer, then I force a garbage collection. > To my surprise the timer is still sparking off events! Here's the code: > > > using System.Timers; > using System; > > public class TimerTest > { > public TimerTest() > { > var timer = new Timer(1000); > timer.Elapsed += (o, e) => { Console.WriteLine("Timer elapsed"); }; > timer.Start(); > } > > public static void Main() > { > { > var timerTest = new TimerTest(); > } > > Console.ReadLine(); > GC.Collect(); > GC.WaitForPendingFinalizers(); > GC.Collect(); // necessary? does not seem to help > Console.ReadLine(); > } > } > > > Can someone please explain why the Elapsed event is still firing after > the first ReadLine()? Thanks in advance! > > Regards, > > Daniel Lidstr�m > >
First
|
Prev
|
Next
|
Last
Pages: 1 2 3 4 Prev: PDF font features Next: Real Programmers (TM) use MSFT C# not Linux languages (sez an expert) |