Click here to Skip to main content
14,920,001 members

Comments by Daniel Grunwald (Top 9 by date)

Daniel Grunwald 23-Apr-11 17:19pm View
   
This only applies to System.Threading.Timer. The other timers keep themselves alive until explicitly stopped.
Daniel Grunwald 23-Apr-11 17:18pm View
   
The reference chain here is actually:
static list of timer callbacks (within .NET runtime) => new System.Threading.TimerCallback(...) => mtd.TimerCall(o){} => mtd => m_timer
If the timer would get garbage collected, it would deregister the callback from the static list. But it can't get garbage collected, since it still is reachable from a GC root. The GC can't look into finalizers to see that they would remove the last remaining reference.

So in a sense, this is a "cycle" that the GC can't deal with - but that's because the GC can't look into the future to see that if it collected an object that is still reachable, it would become unreachable.

But your solution reads as if the GC couldn't deal with cycles of references - that's giving the wrong impression, as the GC can handle those fine. One only needs to be aware that the whole cycle will live as long as the longest-lived object within the cycle.
Daniel Grunwald 23-Apr-11 17:03pm View
   
Yes, it depends on the timer implementation. System.Threading.Timer in .NET 4.0 indeed looks like it keeps only the delegate alive, so breaking the reference chain from the delegate to the timer is sufficient to get the timer object collected (which will stop the timer in its finalizer).
However, System.Timers.Timer and System.Windows.Forms.Timer do keep themselves alive, so those need to be stopped explicitly.
Daniel Grunwald 23-Apr-11 12:07pm View
   
A System.Threading.Timer starts automatically when the constructor is called.
If you add a "m_timer.Start()" call to your WinForms code, you'll find that the same memory leak will occur.
Daniel Grunwald 23-Apr-11 11:56am View
   
The GC can handle circular references just fine, even with events and delegates.
The "event problem" only occurs when you have a long-lived object as events source, and a short-lived object as event handler: the delegate will keep the event handler alive as long as the event source lives.
In the worst case (event source lives forever, e.g. static event), the event handlers will never be garbage collected.
However, if the event source has a short lifetime, you do not need to unregister event handlers.
Daniel Grunwald 26-Nov-10 15:17pm View
   
To clarify: "almost always" means "always except in a weird case related to COM interop". There's no way "new" returns null in pure C# code.
Daniel Grunwald 28-Oct-10 16:27pm View
   
This explanation is incorrect.
The number is generated at COMPILE TIME.
Both List<string> and List<int> will use the class List`1. The `1 is simply appended by the compiler to disambiguate the class name (because C# allows having both List<T> and List<T,S> in the same namespace). It merely indicates the number of type parameters.
Daniel Grunwald 28-Oct-10 16:26pm View
   
This explanation is incorrect.
The number is generated at COMPILE TIME.
Both List<string> and List<int> will use the class List`1. The `1 is simply appended by the compiler to disambiguate the class name (because C# allows having both List<t> and List<t,s> in the same namespace)
Daniel Grunwald 9-Aug-10 16:45pm View
   
The Length property restricts the size to 2147483647 characters. .NET strings are stored as Unicode (UTF-16), so the maximum size is about 4 GB.
Of course, there may be other restrictions in the .NET runtime that prevent objects from being more than 2 GB (I think even the 64-bit .NET runtime has this restriction), so the actual limit may be a lot lower than that.
In my experience, anything larger than 200M characters and you're very likely to run into OutOfMemoryExceptions.