Does Scripting.Dictionary's RemoveAll() method release all of its elements first? - vb6

In a VB6 application, I have a Dictionary whose keys are Strings and values are instances of a custom class. If I call RemoveAll() on the Dictionary, will it first free the custom objects? Or do I explicitly need to do this myself?
Dim d as Scripting.Dictionary
d("a") = New clsCustom
d("b") = New clsCustom
' Are these two lines necessary?
Set d("a") = Nothing
Set d("b") = Nothing
d.RemoveAll

Yes, all objects in the Dictionary will be released after a call to RemoveAll(). From a performance (as in speed) standpoint I would say those lines setting the variables to Nothing are unnecessary, because the code has to first look them up based on the key names whereas RemoveAll() will enumerate and release everything in one loop.

RemoveAll will remove all the associations from the Dictionary: both the keys and values.
It would be a reference leak for the Dictionary to keep a reference to the values in the Dictionary.

If there are no other variables that reference the items in the collection then those objects should be handed to the Garbage Collector to be cleaned up the next time the GC is run.
If you, for example do this where sObj is a static variable somewhere then the when the GC is invoked next by the system, the first object will be cleaned up but the second which still is referenced by sObj will not.
d("a") = New clsCustom
d("b") = New clsCustom code.
sObj = d("b")
d.RemoveAll()

Related

Funny result in New and Nothing

I'm using VB6, and just found something funny in my team member's code.
Dim anObject As New AClass
Set anObject = Nothing
anObject.DoingSomeThing
What I expect, the code should fail since anObject is set to Nothing now, but the code can work without error?
If I change the above codes to
Dim anObject As AClass
Set anObject = New AClass
Set anObject = Nothing
anObject.DoingSomeThing
This will fail since anObject is Nothing now.
I cannot understand why the code can work at 1st code but fail in 2nd code?
In VB6, if you declare some object As New, then VB internally places hidden code to check object presence and optionally instantiate object before every use of that object. Explictly such code would look as:
If anObject Is Nothing Then Set anObject = New AClass
In second case you have to maintain object presence yourself.
Note - better do not use As New. Its performance is worse and if you ever need to port your project to VB.NET, then behavior changes; in VB.NET declaring variable As New just initializes it at first, but doesn't re-initailize it after setting it to Nothing.

Find all references to an object in Lua

I have a memory leak in the Lua part of my application. For whatever reason, my object is not getting deleted when it should (even when I call collectgarbage("collect")). I assume this means I have a dangling reference somewhere.
So how may I obtain a list of where various references to an object reside? For example:
obj = MyObject()
ref = obj
tbl = {obj}
obj = nil
print(getreferences(obj)) -- should print something like _G.ref, _G.tbl[1]
I would simply write my own function for this, but it would not be able to find references contained inside of closures. Any advice?
There's a tool to traverse the whole Lua universe. See http://lua-users.org/lists/lua-l/2006-07/msg00110.html

Cocoa's NSDictionary: why are keys copied?

All objects used as keys in NS(Mutable)Dictionaries must support the NSCopying protocol, and those objects are copied when they're used in the dictionary.
I frequently want to use heavier weight objects as keys, simply to map one object to another. What I really mean when I do that is effectively:
[dictionary setObject:someObject forKey:[NSValue valueWithPointer:keyObject]];
("When I come back and hand you this same key object instance again, get me that same value out.")
...which is exactly what I end up doing to get around this design sometimes. (Yes, I know about NSMapTable in desktop Cocoa; but e.g. iPhone doesn't support this.)
But what I don't really get is why copying the key is necessary or desirable in the first place. What does it buy the implementation or caller?
The copy ensures that the values used as keys don't change "underhand" while being used as keys. Consider the example of a mutable string:
NSMutableString* key = ...
NSMutableDictionary* dict = [[NSMutableDictionary alloc] init];
[dict setObject: ... forKey: key];
Let's assume that the dictionary did not copy the key, but instead just retained it. If now, at some later point, the original string is modified, then it is very likely that you are not going to find your stored value in the dictionary again even if you use the very same key object (i.e., the one key points to in the example above).
In order to protect yourself against such a mistake, the dictionary copies all keys.
Note, by the way, that it is simple enough to define -copyWithZone: as just doing return [self retain]. This is allowed and good code if your object is immutable, and the NSCopying contract is specifically designed such that the object returned has to be (sorta, kinda) immutable:
Implement NSCopying by retaining the original instead of creating a new copy when the class and its contents are immutable.
(from NSCopying Reference)
and
The copy returned is immutable if the consideration “immutable vs. mutable” applies to the receiving object; otherwise the exact nature of the copy is determined by the class.
(from -copyWithZone: Reference)
Even if your objects are not immutable, you might get away with that implementation if you only ever use identity-based equality/hash implementations, i.e., implementations which are not affected in any way by the object's internal state.
If you want to store pointers as keys then you'll need to wrap them in a NSValue object with +valueWithPointer:.
Since iOS 6 if you want to use pointers as keys, you can use the NSMapTable object, see http://nshipster.com/nshashtable-and-nsmaptable/
You can specify whether keys and/or values are stongly or weakly held:
NSMapTable *mapTable = [NSMapTable mapTableWithKeyOptions:NSMapTableStrongMemory
valueOptions:NSMapTableWeakMemory];
Another option that could be appropriate sometimes is to use NSCache, which holds keys strongly and is actually thread-safe.

How can I stop execution in the Visual Studio Debugger when a private member variable changes value?

Let's say my class has a private integer variable called count.
I've already hit a breakpoint in my code. Now before I press continue, I want to make it so the debugger will stop anytime count gets a new value assigned to it.
Besides promoting count to a field and setting a breakpoint on the set method of the field, is there any other way to do this?
What you're looking for is not possible in managed code. In C++ this is known as data break point. It allows you to break whenever a block of memory is altered by the running program. But this is only available in pure native C++ code.
A short version of why this is not implemented is that it's much harder in managed code. Native code is nice and predictable. You create memory and it doesn't move around unless you create a new object (or explicitly copy memory).
Managed code is much more complex because it's a garbage collected language. The CLR commonly moves objects around in memory. Therefore simply watching a bit of memory is not good enough. It requires GC interaction.
This is just one of the issues with implementing managed break points.
I assume you're trying to do this because you want to see where the change in value came from. You already stated the way I've always done it: create a property, and break on the set accessor (except that you must then always use that set accessor for this to work).
Basically, I'd say that since a private field is only storage you can't break on it because the private field isn't a breakable instruction.
The only way I can think do do this, is to right click on the variable, and select "Find all references". Once it finds all the references, you can create a new breakpoint at each point in the code where the variable is assigned a value. This would probable work pretty well, unless you were passing the variable in by reference to another function and changing the value in there. In that case, you'd need some way of watching a specific point in memory to see when it changed. I'm not sure if such a tool exists in VS.
Like ChrisW commented. You can set a 'Data Breakpoint' but only for native (non-managed) code. The garbage collector will move allocated memory blocks around when the garbage collector runs. Thus, data breakpoints are not possible for managed code.
Otherwise, no. You must encapsulate access to your item for which you want to 'break on modify'. Since its a private member already, I suggest following Kibbee's suggestion of setting breakpoints wherever its used.
Besides promoting count to a field and setting a breakpoint on the set method of the field, is there any other way to do this?
Make it a property of a different class, create an instance of the class, and set a breakpoint on the property.
Instead of ...
test()
{
int i = 3;
...etc...
i = 4;
}
... have ...
class Int
{
int m;
internal Int(int i) { m = i; }
internal val { set { m = value; } get { return m; } }
}
test()
{
Int i = new Int(3);
...etc...
i.val = 4;
}
The thing is that, using C#, the actual memory location of everything is being moved continually: and therefore the debugger can't easily use the CPU's 'break on memory access' debugging register, and it's easier for the debugger to, instead, implement a code-location breakpoint.

When must I set a variable to "Nothing" in VB6?

In one of my VB6 forms, I create several other Form objects and store them in member variables.
Private m_frm1 as MyForm
Private m_frm2 as MyForm
// Later...
Set m_frm1 = New MyForm
Set m_frm2 = New MyForm
I notice that I'm leaking memory whenever this (parent) form is created and destroyed. Is it necessary for me to assign these member variables to Nothing in Form_Unload()?
In general, when is that required?
SOLVED: This particular memory leak was fixed when I did an Unload on the forms in question, not when I set the form to Nothing. I managed to remove a few other memory leaks by explicitly setting some instances of Class Modules to Nothing, as well.
Actually, VB6 implements RAII just like C++ meaning that locally declared references automatically get set to Nothing at the end of a block. Similarly, it should automatically reset member class variables after executing Class_Terminate. However, there have been several reports that this is not done reliably. I don't remember any rigorous test but it has always been best practice to reset member variables manually.
#Matt Dillard - Did setting these to nothing fix your memory leak?
VB6 doesn't have a formal garbage collector, more along the lines of what #Konrad Rudolph said.
Actually calling unload on your forms seems to me to be the best way to ensure that the main form is cleaned up and that each subform cleans up their actions.
I tested this with a blank project and two blank forms.
Private Sub Form_Load()
Dim frm As Form2
Set frm = New Form2
frm.Show
Set frm = Nothing
End Sub
After running both forms are left visible. setting frm to nothing did well... nothing.
After settign frm to nothing, the only handle open to this form is via the reference.
Unload Forms(1)
Am I seeing the problem correctly?
Josh
Objects in VB have reference counting. This means that an object keeps a count of how many other object variables hold a reference to it. When there are no references to the object, the object is garbage collected (eventually). This process is part of the COM specification.
Usually, when a locally instantiated object goes out of scope (i.e. exits the sub), its reference count goes down by one, in other words the variable referencing the object is destroyed. So in most instances you won't need to explicitly set an object equal to Nothing on exiting a Sub.
In all other instances you must explicitly set an object variable to Nothing, in order to decrease its reference count (by one). Setting an object variable to Nothing, will not necessarily destroy the object, you must set ALL references to Nothing. This problem can become particularly acute with recursive data structures.
Another gotcha, is when using the New keyword in an object variable declaration. An object is only created on first use, not at the point where the New keyword is used. Using the New keyword in the declaration will re-create the object on first use every time its reference count goes to zero. So setting an object to Nothing may destroy it, but the object will automatically be recreated if referenced again. Ideally you should not declare using the New keyword, but by using the New operator which doesn't have this resurrection behaviour.
#Martin
VB6 had a "With/End With" statement that worked "like" the Using() statement in C#.NET. And of course, the less global things you have, the better for you.
With/End With does not working like the Using statement, it doesn't "Dispose" at the end of the statement.
With/End With works in VB 6 just like it does in VB.Net, it is basically a way to shortcut object properties/methods call. e.g.
With aCustomer
.FirstName = "John"
.LastName = "Smith"
End With
Strictly speaking never, but it gives the garbage collector a strong hint to clean things up.
As a rule: do it every time you're done with an object that you've created.
Setting a VB6 reference to Nothing, decreases the refecences count that VB has for that object. If and only if the count is zero, then the object will be destroyed.
Don't think that just because you set to Nothing it will be "garbage collected" like in .NET
VB6 uses a reference counter.
You are encouraged to set to "Nothing" instanciated objects that make referece to C/C++ code and stuff like that. It's been a long time since I touched VB6, but I remember setting files and resources to nothing.
In either case it won't hurt (if it was Nothing already), but that doesn't mean that the object will be destroyed.
VB6 had a "With/End With" statement that worked "like" the Using() statement in C#.NET. And of course, the less global things you have, the better for you.
Remember that, in either case, sometimes creating a large object is more expensive than keeping a reference alive and reusing it.
I had a problem similar to this a while back. I seem to think it would also prevent the app from closing, but it may be applicable here.
I pulled up the old code and it looks something like:
Dim y As Long
For y = 0 To Forms.Count -1
Unload Forms(x)
Next
It may be safer to Unload the m_frm1. and not just set it to nothing.
One important point that hasn't yet been mentioned here is that setting an object reference to Nothing will cause the object's destructor to run (Class_Terminate if the class was written in VB) if there are no other references to the object (reference count is zero).
In some cases, especially when using a RAII pattern, the termination code can execute code that can raise an error. I believe this is the case with some of the ADODB classes. Another example is a class that encapsulates file i/o - the code in Class_Terminate might attempt to flush and close the file if it's still open, which can raise an error.
So it's important to be aware that setting an object reference to Nothing can raise an error, and deal with it accordingly (exactly how will depend on your application - for example you might ignore such errors by inserting "On Error Resume Next" just before "Set ... = Nothing").

Resources