I've done a little playing around in the console and debugger, but I've still got some questions about how new and gen work differently from each other.
What is the difference between using new to generate a struct verse using gen to generate a struct?
Does "gen" use existing allocated memory and "new" allocate new memory? or both allocate memory?
Does "new" generate everything like a "gen" statement?
In cdnshelp it says "new" is a shallow struct, meaning struct fields are not allocated. Is this also true of "gen"?
Calling new will allocate memory for the struct (except for other internal struct fields) and call that struct's init() function.
Calling gen will do everything new does, but also randomize the struct's fields. If any of the struct's fields are other structs, it will call gen on them too.
Related
Since ARC doesn't apply to struct and enum, then how are they deallocated from the memory? I have to get stuck when it asked in the interviews and try to find the correct answer but can't find much info on it googling. I know swift is smart at handling value types. But how?
The memory management of objects (instances of classes) is relatively difficult, because objects can outlive a function call, the life of other objects, or even the life of the threads that allocated them. They're independent entities on the heap, that need book keeping to make sure they're freed once they're not needed (once they're no longer referenced from any other threads/objects, they're unreachable, thus can't possible be needed, so are safe to delete).
On the other hand, structs and enums just have their instances stored inline:
If they're declared as a global variable, they're stored in the program text.
If they're declared as a local variable, they're allocated on the stack (or in registers, but never mind that).
If they're allocated as a property of another object, they're just
stored directly inline within that object.
They're only ever deleted
by virtue of their containing context being deallocated, such as when
a function returns, or when an object is deallocated.
We all know an array in swift is a value type, this means after copying or assigning an array to another, modify the new array will not effect the old one. Such as:
var a = ["a", "b", "c", "d", "e"]
var b = a
b[0] = "1"
print(a[0]) // a
print(b[0]) // 1
But I'm wondering how could an array work like that. The length for a 'var' array is dynamical. Usually we must alloc some heap memory to contain all the values. And I do peek some source codes for struct Array, the underlining buffer for an array is implemented using a class. But when copying a struct which contains class or memory pointer member, the class and alloced memory will not copied by default.
So how could an array copy its buffer when copy or assign it to another one?
Assignment of any struct (such as Array) causes a shallow copy of the structure contents. There's no special behavior for Array. The buffer that stores the Array's elements is not actually part of the structure. A pointer to that buffer, stored on the heap, is part of the Array structure, meaning that upon assignment, the buffer pointer is copied, but it still points to the same buffer.
All mutating operations on Array do a check to see if the buffer is uniquely referenced. If so, then the algorithm proceeds. Otherwise, a copy of the buffer is made, and the pointer to the new buffer is saved to that Array instance, then the algorithm proceeds as previously. This is called Copy on Write (CoW). Notice that it's not an automatic feature of all value types. It is merely a manually implemented feature of a few standard library types (like Array, Set, Dictionary, String, and others). You could even implement it yourself for your own types.
When CoW occurs, it does not do any deep copying. It will copy values, which means:
In the case of value types (struct, enum, tuples), the values are the struct/enum/tuples themselves. In this case, a deep and shallow copy are the same thing.
In the case of reference types (class), the value being copied is the reference. The referenced object is not copied. The same object is pointed to by both the old and copied reference. Thus, it's a shallow copy.
On Apple's documentation on Substring, is says:
Don’t store substrings longer than you need them to perform a specific operation. A substring holds a reference to the entire storage of the string it comes from, not just to the portion it presents, even when there is no other reference to the original string. Storing substrings may, therefore, prolong the lifetime of string data that is no longer otherwise accessible, which can appear to be memory leakage.
I feel confused that String is a value type in Swift and how does it lead to memory leak?
Swift Arrays, Sets, Dictionaries and Strings have value semantics, but they're actually copy-on-write wrappers for reference types. In other words, they're all struct wrappers around a class. This allows the following to work without making a copy:
let foo = "ABCDEFG"
let bar = foo
When you write to a String, it uses the standard library function isUniquelyReferencedNonObjC (unless it's been renamed again) to check if there are multiple references to the backing object. If so, it creates a copy before modifying it.
var foo = "ABCDEFG"
var bar = foo // no copy (yet)
bar += "HIJK" // backing object copied to keep foo and bar independent
When you use a Substring (or array slice), you get a reference to the entire backing object rather than just the bit that you want. This means that if you have a very large string and you have a substring of just 4 characters, as long as the substring is live, you're holding the entire string backing buffer in memory. This is the leak that this warns you about.
Given the way Swift is often portrayed your confusion is understandable. Types such as String, Array and Dictionary present value semantics but are library types constructed from a combination of value and references types.
The implementation of these types use dynamically allocated storage. This storage can be shared between different values. However library facilities are used to implement copy-on-write so that such shared storage is copied as needed to maintain value semantics, that is behaviour like that of value types.
HTH
Something I've been wondering for a while. I know that in order to free up memory, objects (Such as NSMutableArray) have to be released, but raw data types (Such as int) don't. My question is, at what point does the space in memory that an int is occupying become free?
For example, a class "myClass" has an iVar "int a"
"a" holds the value some integer value.
When "myClass" is deallocated, does the space in memory that was holding the value for "a" become free straight away?
Thanks in advance.
For class ivars, the memory is freed when the object instance is deallocated - upon the last [release] call. For local int (and other primitive) variables, when the function returns. For global and static variables, when the process quits.
Also, you can allocate int's dynamically with malloc(). Then it's freed when you call free().
"a" is included in the memory allocated in "myClass". In other words, when myClass is deallocated, "a" is gone right along with it.
An Objective C object is similar to a pointer to a malloc'd C structure (containing both declared and a few hidden instance variables). When an object is released, the entire C structure memory block, including all internal ivar storage, is free'd (as well as any other dealloc housekeeping required).
Since there is no counterpart to NSValue in Core Foundation, how are we supposed to store C structs in a CFMutableDictionary?
First, you can put an NSvalue in a CFMutableDictionary as-is, so the answer is "use NSValue." But I assume the rest of your question is "without using any Cocoa objects." In that case, just create a non-retaining CFMutableDictionary, and you can put any pointer you want into it. See "Defining Custom Collection Callbacks" for some example code. I use these a lot.
Remember that these still have to be pointers, so you're going to have to allocate your structs on the heap, not the stack. And that means that memory management is now your problem. Of course you could create a custom set of callbacks that do whatever you want, so if you're using boost or something else with its own ref-counting system, you can still implement that with CFMutableDictionary.
And of course you can replace the struct with a small data object. That's usually a lot easier. But different problems need different solutions.
CFMutableDictionary
CFDictionaryAddValue
A CFType object or a pointer value to add to the dictionary.
you just pass a pointer to your struct.