I need to have a few hard coded collection data (ie NSArray, NSDictionary), and I'm wondering what the memory footprint is it like, for example,
- (NSArray *)getDataA
{
NSArray *data = #[ #{#"key": #"value"} ];
return data;
}
And the actual data is way more than the key-value in the above code.
I guess the local variables are stored on stack and the actual value are in heap, but before calling getDataA, do they occupy any memory space?
Thanks!
Keep in mind that a structure such as in the question is created by code executing at runtime, they will not be static. Constant NSStrings are the exception and possibly a few other special cases like some NSNumbers.
Unless you have MBs the size is not really important. Like all optimizations: don't. Do the most clear implementation and then measure.
Related
arrayWithCapacity is a method defined in NSArray.h and implemented in NSArray.m
When I look at the code that GNUStep provided, I can get that arrayWithCapacity is a normal method that calls initWithCapacity:
+ (id) arrayWithCapacity: (NSUInteger)numItems
{
return AUTORELEASE([[self allocWithZone: NSDefaultMallocZone()]
initWithCapacity: numItems]);
}
And initWithCapacity is a simple method that only does self initialization.
- (id) initWithCapacity: (NSUInteger)numItems
{
self = [self init];
return self;
}
Nothing about memory allocation with number of items executed.
What is the advantage of using the arrayWithCapacity method? Is it better to simply use [[NSArray alloc] init]?
The expectation is that providing an explicit size improves memory allocation as there's no need to adjust the size of the array as items are added. In practice, it is just a hint and there's some evidence that it's not actually used (see this objc.io article on The Foundation Collection Classes).
The methods are actually part of NSMutableArray, not NSArray.
It gives the implementation a hint about how many items you like to store so it can already allocate enough memory up-front instead of growing the memory as-needed, which can be expensive as it might involve allocating, copying from the old memory to the new one, deallocate old memory. And if you add a lot of items this growing might happen a lot, so it's more efficient if the NSMutableArray can allocate the required amount of memory in one go.
Remember that it's just a hint and an implementation may ignore it. In fact, CFArray/CFMutableArray does ignore the capacity when creating a mutable array:
static CFArrayRef __CFArrayInit(CFAllocatorRef allocator, UInt32 flags, CFIndex capacity, const CFArrayCallBacks *callBacks) {
struct __CFArray *memory;
UInt32 size;
...
switch (__CFBitfieldGetValue(flags, 1, 0)) {
case __kCFArrayImmutable:
size += capacity * sizeof(struct __CFArrayBucket);
break;
case __kCFArrayDeque:
case __kCFArrayStorage:
break;
}
...
return (CFArrayRef)memory;
}
CFMutableArrayRef CFArrayCreateMutable(CFAllocatorRef allocator, CFIndex capacity, const CFArrayCallBacks *callBacks) {
...
return (CFMutableArrayRef)__CFArrayInit(allocator, __kCFArrayDeque, capacity, callBacks);
}
According to this article linked by #azsromej, NSMutableArray also seems to ignore the hint.
This applies to NSMutableArray since NSArray does not have the method arrayWithCapacity, this also applies to initWithCapacity:
There is a negligible if any advantage to using arrayWithCapacity from a run-time POV. It can be considered a premature optimization.
It does have a disadvantage or taking some time and/or code to come up with a value that very rarely provides a meaningful time advantage and increases the mental load.
It is also considered a hint and may or not be used, that is an implementation detail Apple can change at any tine.
Note: I have made timing tests with and without the capacity hint and the time saved, if any, was a extremely small percentage.
Also see ridiculousfish for more information on NSArray.
Comment by #bbum: "the docs simply state establishes the initial capacity not that the array has allocated memory to hold all of that capacity. Array's backing store are not linearly allocated chunks of memory and the details change with the size of the array."
I would like to print (log) what are the below variables are stored in stack and heap. I want to know where are these below variables are stored in this program. My feel is, except the first two variables , others are storing in heap.
-(void) MyFunction
{
flat value = 9.5; // Stored in Stack?
int count; // Stored in Stack?
NSString *myString = #"Incoming message"; // Stored in Heap
NSArray *myArr = [[NSArray alloc] init]; // Stored in Heap
.......
.......
}
In this case, how do i release those, using 'release'?
How can i print/log where these variables stored in stack/heap?
Does my assumption storing location(heap/stack) mentioned in above program is correct or wrong?
If an allocated objects stored in heap memory, their references will also be in heap only (or) reference will be in stack?
I would like to print (log) what are the below variables are stored in stack and heap. I want to know where are these below variables are stored in this program.
It's very unlikely that you really want to do that, but you can like this:
NSLog(#"value:%p", &value);
NSLog(#"count:%p", &count);
NSLog(#"myString:%p", myString);
NSLog(#"myArr:%p", myArr);
Regarding where they're stored:
float value = 9.5; // Stored in Stack?
Probably, if you actually modify it. It might also be stored in a register. Or it might be completely optimized away if it turns out to be constant. The above log statements will force it to be stored on the stack (so it can have an address), so asking where the variable is stored can actually change where it is stored.
But yes, as a back-of-the-envelope approximation of unoptimized code, automatic variables are stored on the stack.
int count; // Stored in Stack?
Again, probably. Of course if you never access it, it could be completely optimized away.
NSString *myString = #"Incoming message"; // Stored in Heap
The constant string that this points to is stored in the text segment (in the code itself). The myString pointer itself is an automatic variable, however, and that is stored on the stack as above.
NSArray *myArr = [[NSArray alloc] init]; // Stored in Heap
This could be optimized down to a constant empty array stored in the framework. Or it could be on the heap.
In this case, how do i release those, using 'release'?
No. You manage these using ARC, which will manage retains and releases for you. You should not manually call release in most code.
If an allocated objects stored in heap memory, their references will also be in heap only (or) reference will be in stack?
The pointer variable itself is stored on the stack.
You can log the values of pointer variables with the %p format specifier, e.g.: NSLog(#"%p", myString);
However that in itself won't tell you whether a given address is in a particular memory segment (though you can generally make some educated guesses based on address ranges -- for example, stack addresses begin at the end of a program's address space, so their values tend be much larger than heap addresses; distinguishing heap addresses from static addresses can be a little tricker though).
You're correct in thinking that value and count will be store on the stack, but the object myString refers to will be stored in static memory rather than in heap. However, myArr will be allocated in heap.
Automatic variables (method and function arguments, and local variables not explicitly declared static) are allocated on the stack, regardless of the values you initialize them with.
Wondering, After building nsmutablearray should i convert it to nsarray for performance benefit? If i am going to keep and use that array for quite sometime.
No. The conversion itself will cost time and CPU cycles and you won't gain anything from the conversion.
I would actually say it depends. If I create a NSMutableArray within a method and needs to return it, then generally unless the caller requires the ability to directly modify the array values, I will return the NSMutableArray as a NSArray for the sake of simlicity and to reduce the memory footprint of the application.
However, if I am creating the NSMutableArray for direct consumption within the current method, then I seen no benefit of casting it to a NSArray.
If we type
MyObject *obj = [[MyObject alloc] init];
"obj" is a pointer to the memory address.
...When we create an int, we type:
int x = 10;
Why don't we type?
int *x = 10;
The question is, why do we need a pointer to object and not int, float, etc...
Efficiency.
Moving an int from one place to another is easy. Moving an object needs a little bit more work from the CPU. Moving the address of an object is as easy as moving an int.
In plain C, it is common to handle pointers to structs for the same reason. C makes it easy with the -> operator.
There are languages where you can create objects “without a pointer”, on the stack. C++, for example. One great thing about having objects on the stack is that they get automatically deallocated when the scope ends, which helps with memory management. It’s also faster.
One bad thing about having objects on the stack is that they get automatically deallocated when the scope ends and the stack disappears. And since objects are usually longer-lived than local variables, you would have to copy the object’s memory somewhere. It’s entirely possible, but it complicates matters.
And it’s not just the memory lifecycle that’s complicated with stack-based objects. Consider assignment, foo = bar for two object types. If the objects are always pointers (Class*), you just assigned a pointer and got two pointers to the same objects; easy. If foo is stack-based (Class), the assignment semantics starts to get blurry – you could well end with a copy of the original object.
Introducing a rule that all objects are allocated on the heap (“with pointers”) is a great simplification. And as it happens, the speed difference doesn’t matter that much, and the compiler can now also automatically insert code to deallocate heap-based objects after they go out of scope, so it’s generally a win-win situation.
You can have pointer for int, float as well.
Objects are created on heap. To access it, you need the address. Thats why they are of pointer types.
Because that is the nature of an object.
Objective-C is directly derrived from C. That is why objects are referred to as pointers. An int-type variable of the size of an memory address is a pointer.
In the end, an object in memory is not much different from an struct in memory.
However, when working in Objective-C it is advisable to think of these variables as references of objects rather than pointers to an object's memory areas. Think of them like Java does and do not spend much thoughts on how the system manages the references. There are far more important things to think of such as alloc/retain vs. release/autorelease or following the much easier ARC rules respectively.
BTW:
MyObject obj;
That would declare an object, not a pointer. It is not possible in Objective-C (afaik) and certainly not reasonable. But if it was reasonable and possible, that is what the syntax would look like.
int *x;
That does create a pointer to an int. For using it you would have to allocate memory and assign its address to x. Rarerly reasonable in Objective C either but quite useful in standard C.
its the difference between objects being on the stack or the heap.
going int x = 10 x is now on the stack. int *x = 10 is just simply wrong (well most likely not what you want) since that is declaring a pointer to address 10 whatever that may be. you would want int *x = malloc(sizeOf(int)); as CodaFi suggested. that will allocate memory on the heap of the size of an int.
going MyObject *obj = [[Myobject alloc] init]; the compiler behind the scenes is allocating your object to the heap for you, but its basically the same principle
I have a question regarding NSArray and NSMutableArray. I understand the difference between two primarily that NSArray is immutable and NSMutableArray is mutable. And as far as my research goes, there performance is kind of same too. There is one thing that I could not find a good answer for and that is if NSMutableArray uses more memory than NSArray and if NSMutableArray is somehow harsher on memory than NSArray.
I would really appreciate the suggestions and explanation.
Thanks
Vik
NSMutableArray uses slightly more memory for two (er, four, see comments) reasons:
1) Because it can change size, it can't store the contents inside the object and must store a pointer to out of line storage as well as the extra malloc node for the storage
2) Because it would be very slow to resize one element at a time as things are added, it resizes in chunks, which may result in some unused space.
It's like wondering about the difference between a standard array or a std::vector. A mutable data structure does require to do more things, not primarily memory (as the one required by NSMutableArray and NSArray could be equal) but it requires to be dynamically resizable and to manage all specific operations like insertions and removals which are not necessary with an immutable array: the dimension is decided when the object is allocated at it is constant.
For normal use there is no noticeable performance difference.
However, If you return an NSArray from a method that internally uses a mutable array for building the response, then I found that a copy of the temporary array can take significant amount of time.
In some instances in DTCoreText I found the [NSMutableArray copy] to NSArray would take 40% of the method time in Instruments. I.e. Returning the mutable array halved the method time.
So when evaluating NSArray versus mutable performance I recommend you direct your attention towards avoiding copying objects. In tight loops or internal methods you should prefer to avoid copying.