Mike_R Posted February 27, 2005 Posted February 27, 2005 (edited) The following relates to this post here: Compile Form to DLL Post #24. The details of that are not important, but I was knocking up a quick form for Realolman, and used the some code within Form1 to create a New Form2. The code looks straight-forward (and it seems to work fine), but there's something odd about it... I'm going to translate the code to C# here. I just wanted to be certain that VB was not doing some sort of "special hand-holding" behind the scenes. I didn't think that it was (and the following proves that it wasn't), but I just wanted to be certain. Here's the scenario: There are two Form Classes, called 'class Form1' and 'class Form2'. The 'Form2' class has no code in it at all. The 'Form1' class has only one Button Control ('button1') and when clicked it creates and shows a New Form2 class. Simple, right? Here is all the code within Form1:namespace csFormLifetimeTester { class Form1 : Form { public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { } private void button1_Click(object sender, EventArgs e) { Form2 frm2 = new Form2(); frm2.Show(); } } } And it runs fine... Every time you click the 'button1' you get a new 'Form2'. Perfect. Or is it? What bothered me is that I was sloppy and had the button1_Click() event procedure holding its 'Form2' reference locally in the 'frm2' variable. Then the call to frm2.Show() is modeless and so the code runs out and frm2 is set = null... So I was thinking "wow, this is dangerous... at the next GC.Collect() call, all these Form2's -- which look alive -- will be collected! The User is in for quite a shock!" And the Programmer (me!) has fallen into an easy trap, as the incorrectness of this approach is not evident when you run it... In fact, if the Application is small and does not use the Heap much, GC.Collect() may never occur and there may never be a problem with this. So just to make sure my thinking on this was correct, I changed the button1_Click() event to the following:private void button1_Click(object sender, EventArgs e) { Form2 frm2 = new Form2(); frm2.Show(); frm2 = null; GC.Collect(); GC.WaitForPendingFinalizers(); } We set frm2 = null and then force the Heap to be collected... And guess what? The Form2 still persists, as if absolutely nothing has happened. Wow. In fact, you can keep hitting the 'button1' and create multiple instances of this 'Form2' class, like in in the "Sorcerer's Apprentice". But what the heck is keeping all these instances alive? So I'm left with two theories as to how this might be occurring: (1) I suppose that my best guess is that the Form has some sort of code running in a loop at all times in the background. As long as it's running, it is "alive". The loop, I guess, is simply "event listening" but it is either implicitly keeping itself alive, or possibly even explicitly doing so by making a continuous call to GC.KeepAlive(this) in a loop, or, well, really it just needs the GC.KeepAlive() call in the line just after the loop exits... Obviously a call to Form Close or really .Dispose() ends this process and allows the form to "die". (2) There could be a "master set" of Form references in the background??? This feels very VB6-ish though -- the old "Forms Collection" that is secretly holding a reference to everything in the background. Sounds very ugly, and I know that VB.Net it working on such stuff for v2.0 (and my-god, I really hope they re-consider this. :(). I actually expect that this is not the reason... well I certainly hope not! Anyway, I have yet to read my .Net book's chapter on "Forms & Controls", so maybe this is all spelled out right there... But I was wondering what other people's thoughts were on this or if anyone definitively knew what is going on behind the scenes to keep a form "alive"? -- Mike (See attached if anyone feels like kicking this around...)csFormLifetimeTest.zip Edited February 28, 2005 by PlausiblyDamp Quote Posting Guidelines Avatar by Lebb
Talyrond Posted February 27, 2005 Posted February 27, 2005 Hi very interesting, like you say setting frm2 to null does not kill the form, its there to be seen! But stepping back a bit to the first piece of code, as you create each form, you are not loosing them, you would use the Activate event to access each instance of the form, so in other word each instance will activate its own Activate event when it gets the focus. Of course if you needed to work on a form that did not have the focus you would have to store a reference to it when you created it. So my best guess as to what is keeping it alive, would be your Number 1) because of the Activate event! Quote
Administrators PlausiblyDamp Posted February 28, 2005 Administrators Posted February 28, 2005 How the GC decides an object is suitable for collection is a little bit more complicated than just variable references. Each application has a series of 'roots' - global variables, local references, en-registered variables; each of these would keep an object alive. Only guessing here but I would imagine that as the form process a windows message pump windows itself is acting as a root for the variable. Quote Posting Guidelines FAQ Post Formatting Intellectuals solve problems; geniuses prevent them. -- Albert Einstein
Mike_R Posted February 28, 2005 Author Posted February 28, 2005 Hey Plausibly, yeah, I agree with the message pump... It's interesting though, because windows itself uses messaging that are effectively weak pointers. The form itself must have some sort of processing loop going on... If this processing loop is constantly accessing (or at least conditionally/potentially accessing) 'this' then that would be enough to keep it alive. So this loop is basically creating an enregistered object pointer to 'this'. What I find interesting is that such a pointer is implicitly "strong" -- there is no way for it to be a weak pointer here, even though a weak pointer really is (theoretically) what one would prefer (so that the object/form could release). But, that, of course, would be phenomenally unsafe: potentially "ripping out" the object out from under the procedure running it. Hmm... you know what, I suppose that they could have this processing loop use weak pointers... On the surface, it would seem that the constant check to see 'If WeakPointer.Target Is Nothing Then' would be a pain and make for slightly more complicated coding (and slightly slower execution), but this is no big deal for an event-handling loop, which is mostly spinning it's wheels anyway, just waiting for something to happen. Huh, so I guess maybe this could be done differently? I obviously don't know a thing about what's going on in the background here, so maybe I shouldn't even be speculating... but I think this is all interesting. Quote Posting Guidelines Avatar by Lebb
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.