I was wondering if someone could tell what happens with regards to memory when the following happens:
Dict = New Dictionary --- Col = New Collection
Dict.Add Key, CustomClassOne
Dict.Add Key2, CustomClassTwo
Dict.Add Key3, CustomClassThree
Dict.Remove Key3
At this point is Key3 removed from memory or would I have to Set Dict.Item(Key3) = Nothing to remove it from memory?
Set Dict = Nothing '// will this remove All the above added custom class objects?
Set Col = Nothing '// Same question as above
Ugh VB memory management.... TY for your time,
- Austin
VB is reference counted.
The rules of when an object is released from memory is simple.. it happens when there are no more references to that object. Each time an object goes out of scope (such as the end of a function) its reference count is decreased; which may in turn cause any objects which were referenced by this object to have their reference counts decreases too; and if their reference counts get to 0, they too are released from memory.
This is why there is usually no need to set an object's reference to Nothing... that will decrease its reference count, but that will also happen when it goes out of scope.
So to answer your question:
Dict.Remove Key3 is all that is required to remove CustomClassThree and Key3 from memory (as long as you don't have other references pointing to this object).
Set Dict = Nothing will remove everything from memory, but this would happen anyway when it goes out of scope (again assuming there are no other references pointing to the objects it contains).
Col doesn't seem to have much to do with the other statements and would be removed from memory when it goes out of scope without needing to set Col = nothing
Note:
The purpose of setting a reference to nothing is only really useful if you have objects which both have references to each other. Look up circular references for the details
With both Scripting.Dictionary and Collection instances when the last reference to the object is gone then the object references they hold are released. Whether or not the objects themselves are deallocated depends on whether or not another variable holds a reference to the same object.
Think of each reference as a rope holding a rock above an abyss. Until the last rope is cut the rock doesn't drop out of existence.
Removing an item from a Dictionary or Collection cuts that one rope.
Related
I alread know, that a dynamic array is automatically deallocated/freed after use.
Does the same applies for resizing, especially decreasing? The manual and most help sites only cover increasing the array size.
test: array of TLabel;
SetLength(test, 10);
// fill array here
SetLength(test, 2); // <=== are entries 3-10 are automatically destroyed?
are entries 3-10 are automatically destroyed?
No, they are not automatically destroyed because those entries are dynamically allocated (and are not managed types). Only the pointers that refer to those items are released. It is your responsibility to destroy the items if necessary, because the compiler has no way to guarantee you wouldn't still use them from another reference (or have already destroyed them).
I must also point out that technically items "3-10" is wrong. Dynamic array are zero based. So the references for entries 2 to 9 are the ones released.
I alread know, that a dynamic array is automatically deallocated/freed after use
In addition, your question indicates you don't properly understand this. It seems you believed that when your array goes out of scope the labels referenced would be automatically destroyed. This is incorrect!
No matter where how or why some/all dynamic array entries are released Delphi won't automatically destroy objects types or any dynamically allocated pointer memory. Delphi only automatically releases memory for primitives (Integer, TDateTime, Double short strings), records and managed types1 (interfaces, long strings, other dynamic arrays).
1 Of course this is via reference counting. I.e. reference is reduced by 1; and the underlying object/string/array is released if and only if refCount is reduced to zero.
As whosrdaddy pointed out, if you want automatic destruction of contained objects, then you need to use a container that implements an ownership concept. TObjectList is an example. Although it doesn't work exactly like a dynamic array, it's behaviour is similar enough that it can usually be used as a replacement very easily.
My knowledge of ARC has been tested today, i stumbled on this article and it has an example under the heading "Nesting of statements" which in my mind seems wrong.
In the example they show embedded above, the line highlighted with a green underline says that the string alloced inside the function would first get a retain count +1 when being created, then +1 again when adding to the array, then once the array is nil'ed after the for loop, the retain count of the string would be reduced by 1, leaving the original string with a retain count of 1, thus not being dealloced.
I would have assumed the compiler would have been smart enough to at least make an object like that not actually have a retain count initially, since if you just had
[[NSString alloc] initWithFormat:#"Name 1"]];
this string being alloced would have nothing pointing to it and would be released when the autorelease pool comes to an end instead of having a retain count of 1 forever. so why would it have different behaviour when its in a parameter of a function? (unless that line does have a retain count of 1 and this is somehow a memory leak? otherwise it could have a retain count of 1 till the end of its scope at most surely, but then that logic would apply if its a parameter as well i would assume)
Is this article wrong or is my understanding of ARC flawed?
The article is wrong.
Your understanding is essentially correct, though the autorelease pool is not used in this case. The sub-expression:
[[NSString alloc] initWithFormat:#"Name 1"]];
returns an owned object, as do all init methods. That object is passed to addObject: and the array also takes ownership. After that ARC sees the string is no longer required by the method and relinquishes its ownership - leaving the array as the only owner.
HTH
ARC is not flawed here. Sounds like the article is wrong.
ARC will release the allocated parameter object as expected while the array keeps its reference. Once the array is released, the object will have no more references and it will also be deallocated, as expected.
I have an instant variable "obj1" in MyClass.h.
#property (nonatomic, retain) NSMutableArray *arrObj1;
and in MyClass.m viewDidLoad method, i have allocated another object "obj2" and assign that to obj1.
- (void)viewDidLoad {
[super viewDidLoad];
NSMutableArray *arrObj2 = [[NSMutableArray alloc] initWithObjects:#"a",#"b",#"c", nil];
NSLog(#"arrObj2 count %lu",(unsigned long)[arrObj2 retainCount]);
self.arrObj1 = arrObj2;
NSLog(#"arrObj1 count %lu",(unsigned long)[self.arrObj1 retainCount]);
NSLog(#"arrObj2 count %lu",(unsigned long)[arrObj2 retainCount]);
}
Here is the output
2015-08-19 11:06:14.461 MyClass[1812:24133] arrObj2 count 1
2015-08-19 11:06:16.332 MyClass[1812:24133] arrObj1 count 2
2015-08-19 11:06:17.327 MyClass[1812:24133] arrObj2 count 2
I am not getting how arrObj2 get retain Count value 2.
please explain me.
Thank you
A more relevant question to your problem is: Why do arrObj and arrObj2 seem to share properties? And the answer is they're two references to the same object. That means the same array is referenced strongly in the same place; that is, arrObj1 and arrObj2 are actually the same array. That's why you see a retainCount of 2, though you shouldn't use retainCount for this. (More on that later.) Compare the addresses of the arrays in the debugger instead; they will be the same. If you add an object to one array, it'll be added to "the other."
You can fix that by using copy on the property declaration instead, or by changing self.arrObj1 = arrObj2 to self.arrObj1 = [arrObj2 mutableCopy] . (Edit: I'm not actually sure changing the property type to copy will help here, since it's a mutable type. It would work if it was just an NSArray, though.)
I hope that answers your question, but now I want to explain why it's the wrong question. Please don't take any offence, because learning this is important and not easy. :)
Think in terms of relationship type, not retain/release
You shouldn't be thinking in terms of retain counts at all, but in terms of strong and weak relationship: A strong relationship expresses an ownership interest in the object, a weak relationship doesn't and will be converted to nil shortly after all ownership interests in the object are removed. Also, note that the retain property type is deprecated: it should be strong in ARC code.
Don't use retainCount.
Don't use retainCount. Or, if you prefer, When to use Retain Count:
Never.
Then there's Apple's official documentation, which begins:
This method is of no value in debugging memory management issues.
Or there's this from bbum, which I consider even better. He goes into great detail about why retainCount is useless, concluding with:
Bottom line: the only time the absolute retainCount can be conclusively used for analytic purposes is if you have the backtrace of every retain and release that contributed to the current retain count’s value (there is another use case, documented at the end). If you have that, then you don’t need the retain count and, fortunately, Instruments is already generally quite adept at producing a per-object inventory of retains and releases for you.
Basically, it's value is not useful. It will return (in some cases) the number of times an object has been retained without releasing. It does not (and can not) take the number of times it has been autoreleased into account. And it will not always return the "correct" value even without considering autorelease, since some objects can never be deallocated from RAM.
in Objective-C an object is a reference type.
The retain count is increased the first time when the object was allocated.
When the object is assigned to arrObj1 the object is not copied when the property is declared as retain or strong so arrObj1 and arrObj2 contain the pointer to the same object. The implicit setter of the property arrObj1 increases the retain counter a second time.
Memory management is the programming discipline of managing the life cycles of objects and freeing them when they are no longer needed.
Managing object memory is a matter of performance; if an application doesn’t free unneeded objects, its memory footprint grows and performance suffers.
Memory management in a Cocoa application that doesn’t use garbage collection is based on a reference counting model. When you create or copy an object, its retain count is 1.
Thereafter other objects may express an ownership interest in your object, which increments its retain count.
The owners of an object may also relinquish their ownership interest in it, which decrements the retain count. When the retain count becomes zero, the object is deallocated (destroyed).
Check this image.
https://developer.apple.com/library/ios/documentation/General/Conceptual/DevPedia-CocoaCore/Art/memory_management.jpg
Hope this help.
After the statement
self.arrObj1 = arrObj2;
the variable arrObj2 and the property self.arrObj1 point to the very same object.
If they point to the same object, and arrObj2 has a reference count of 2, what reference count do you expect self.arrObj1 to have?
Reason why retain count is coming as 2 is because you have used retain for NSMutableArray *arrObj1, so in effect
when you allocate arrObj2 retain count become 1,
the when you assign it to arrObj1 as its having a retain property, count increase - becoming 2.
arrObj2 is same arrObj1 as you have not copied it (as Steven Fisher in above answer pointed out) both has same retain count.
If you make arrObj1 to assign property then count will be remained as 1.
Simply put, the object pointed to by arrObj2 is the same object pointed to by arrObj1. Instruments shows us that this object gets +1 retain count when you called initWithObjects:
And that it got +2 retain count when you called setArrObj1 (i.e. you used the self.arrObj1 = ... syntax):
For demonstrations using Instruments' "Allocations" tool for tracking memory usage, see WWDC 2013 video Fixing Memory Issues and WWDC 2012 video iOS App Performance: Memory. Bottom line, while it will take some practice to efficiently find the correct objects in the "Allocations" tool, this "Record reference counts" feature is invaluable in finding where the strong references to the objects in question were established.
I'm sure you've seen it, but I'd also refer you to the Advanced Memory Management Programming Guide.
When you alloc a new memory area (I call it M) and assign it to obj2, the retainCount of M is 1.
When you do: self.obj1 = obj2.
Because self.obj1 is a retain property, so M will be retain +1, so its retainCount = 2 now.
Cause obj1 & obj2 are references to M, so their retainCount are 2.
Let try [obj1 release] and get retainCount of obj2 again to check.
Hope it helps.
Dynamic arrays are reference counted, and so the memory is freed automatically by the compiler. My question is, when exactly does this automatic freeing occur? Does it happen immediately, or at the end of the containing procedure?
Here is a concrete example
procedure DoStuff;
var data:TBytes;
begin
data:=GetData; // lets say data now contains 1 Gig of data.
DoStuffWithData(data);
// I now want to free up this 1Gig of memory before continuing.
// Is this call needed, or would the memory be freed in the next line anyway?
Finalize(data);
data:=GetMoreData; // The first array now has no remaining references
DoStuffWithData(data);
end
Is the call to Finalize() redundant?
The call to Finalize isn't quite redundant. It's true that the dynamic array's reference count will be decremented on the next line (therefore destroying the array, probably), but that will only happen after the new dynamic array is allocated. Just before the return of GetMoreData, but before the assignment takes place, there will be two dynamic arrays in memory. If you destroy the first one manually in advance, then you'll only have one array in memory at a time.
The second array that you store in data will get destroyed as DoStuff returns (assuming DoStuffWithData doesn't store a copy of the dynamic-array reference elsewhere, increasing its reference count).
When exactly does this automatic freeing occur? Does it happen immediately, or at the end of the containing procedure?
Dynamic memory associated with managed types (dynamic arrays fall into this class) is freed when the reference count is set to 0. This can happen at the following points:
The reference variable is assigned a new value. A call to Finalize can be thought of as the special case where the new values is nil.
The reference variable goes out of scope. For example:
The exit of a function is reached; local variables go out of scope.
An object is destroyed and its members go out of scope.
A pointer to a record is destroyed with the Dispose function; all fields of the record go out of scope.
A unit is finalized and all global variables defined in the unit are finalized.
Note that the various cases above only result in memory being freed when the reference that is being finalized or is leaving scope is the last remaining reference. In other words, when the reference count is 1.
In your specific example, assuming the Finalize is removed, you are creating a new dynamic array and assigning it to a variable that already holds a dynamic array. This then falls into the class described by item 1 in the list above. So in that sense the call to Finalize is superfluous.
Rob has explained the order in which the allocation and deallocation happens which is a good point. To the best of my knowledge that is an implementation detail that is not explicitly documented. However, I'd be astounded if that detail was ever changed.
I'd like to understand what happens when the size of a dynamic array is increased.
My understanding so far:
Existing array elements will remain unchanged.
New array elements are initialised to 0
All array elements are contiguous in memory.
When the array size is increased, will the extra memory be tacked onto the existing memory block, or will the existing elements be copied to a entirely new memory block?
Does changing the size of a dynamic array have consequences for pointers referencing existing array elements?
Thanks,
[edit] Incorrect assumption struck out. (New array elements are initialised to 0)
Existing array elements will remain unchanged: yes
New array elements are initialized to 0: yes (see update) no, unless it is an array of compiler managed types such as string, an other array or a variant
All array elements are contiguous in memory: yes
When the array size is increased, the array will be copied. From the doc:
...memory for a dynamic array is reallocated when you assign a value to the array or pass it to the SetLength procedure.
So yes, increasing the size of a dynamic array does have consequences for pointers referencing existing array elements.
If you want to keep references to existing elements, use their index in the array (0-based).
Update
Comments by Rob and David prompted me to check the initialization of dynamic arrays in Delphi5 (as I have that readily available anyway). First using some code to create various types of dynamic arrays and inspecting them in the debugger. They were all properly initialized, but that could still have been a result prior initialization of the memory location where they were allocated. So checked the RTL. It turns out D5 already has the FillChar statement in the DynArraySetLength method that Rob pointed to:
// Set the new memory to all zero bits
FillChar((PChar(p) + elSize * oldLength)^, elSize * (newLength - oldLength), 0);
In practice Embarcadero will always zero initialise new elements simply because to do otherwise would break so much code.
In fact it's a shame that they don't officially guarantee the zero allocation because it is so useful. The point is that often at the call site when writing SetLength you don't know whether you are growing or shrinking the array. But the implementation of SetLength does know – clearly it has to. So it really makes sense to have a well-defined action on any new elements.
What's more, if they want people to be able to switch easily between managed and native worlds then zero allocation is desirable since that's what fits with the managed code.