How to retrieve memory size of NSArray instance? [duplicate] - ios

I'm trying to find the size of an objective-c object. I'm using something similar to:
NSLog(#"sizeof myObject: %ld", sizeof(*myObject));
That just gives me the size of the pointer though.
What am I doing wrong?

All the compiler knows about is the pointer, which is why you're getting the size of the pointer back. To see the size of the allocated object, use one of the following code snippets:
With ARC:
#import <malloc/malloc.h>
// ...
NSLog(#"Size of %#: %zd", NSStringFromClass([myObject class]), malloc_size((__bridge const void *) myObject));
Without ARC:
#import <malloc/malloc.h>
// ...
NSLog(#"size of myObject: %zd", malloc_size(myObject));
Mike Ash has a decent write-up about some of the Obj-C runtime internals on his Q&A blog: http://mikeash.com/?page=pyblog/friday-qa-2009-03-13-intro-to-the-objective-c-runtime.html

In the GNU Objective-C runtime, you can use (you must import <objc/objc-api.h>:
class_get_instance_size ([MyClass class]);
On Mac OS X you can use (you might need to import <objc/runtime.h>):
class_getInstanceSize ([MyClass class]);
These functions will return how much memory is required to allocate an object, it will not include memory allocated by an object when it is initialised.

First of all, i think its clear from the above posts that the object size is given by malloc_size(myObject), as suggested by Jason and also on the Mac OS reference manual:
"The malloc_size(ptr) function returns the size of the memory block that backs the allocation pointed to by
ptr. The memory block size is always at least as large as the allocation it backs, and may be larger." (http://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man3/malloc_size.3.html)
But if you are interested in finding out the size of the dictionary, keep in mind the following point:
The dictionary stores key-value pairs and does not contain the object itself in the value part but just increases a retain count of the object that was to be "added" and keeps a reference of that object with itself. Now, the dictionary itself just contains the references to the various objects (with a key attached). So if by any chance you are looking for the object size of all the objects refered to by the dictionary, technically that would not be the size of the dictionary. The size of the dictionary would be the sum of the size of all the keys plus the size of all the value-references against the keys plus the size of the parent NSObject. If you are still interested in finding out the size of the refered objects as well, try iterating over the dictionary values array:
NSArray *myArray = [myDictionary allValues];
id obj = nil;
int totalSize = 0;
for(obj in myArray)
{
totalSize += malloc_size(obj);
}
//totalSize now contains the total object size of the refered objects in the dictionary.
Hope that answers the question.

The size of an (objective-c) object is not easy to find because it's not even easy to define. What did you mean with "size of an objective-c object"?
The size of the reference is the size of a pointer (as returned by sizeof(obj_ref)).
The size of the memory that was allocated on creation (+alloc) may be found by the way that Jason gave in the first answer. But this depends on the runtime. The gnu-runtime differs from the apple-runtime. Eventually this is only the memory that is needed by the primitive data types the instance consists of. But not the memory that may be allocated later on (i.e. during initialization (-init)) for objects referenced by the ivars or strings.
An instance of the class
#interface FirstClass
{
int _someInt;
char _someChar;
}
…
#end
needs at least 5 bytes (on many systems - int size may vary) plus static overhead if the runtime needs it. The size of such an object is obvious.
But for an instance of the class
#interface SecondClass
{
FirstClass *_someObject;
char *_name;
id _data;
}
…
#end
the definition of the "size" ist complicated. The object needs 12 bytes (on 32bit systems) plus overhead on allocation. But maybe the name is part of the object and allocated/freed by it. Should the memory which the actual name needs be part of the object's size? And what about the referenced objects?

I would suggest using class_getInstanceSize and malloc_good_size to see what it'll round up to. This will not show the ivars and whatnot inside the returned size.
#import <malloc/malloc.h>
#import <objc/runtime.h>
NSLog(#"Object Size: %zd", malloc_good_size(class_getInstanceSize([yourObject class])));

I think the class description contains the size information -- it is better to look this up than querying using the sizeof operator.

Related

Want Autorelease lifetime with ARC

Transitioning to ARC on iOS.
I have an autoreleased NSString that I use to generate a UTF-8 representation, and rely on pool lifetime to keep the UTF-8 pointer alive:
char *GetStringBuffer(something)
{
NSString *ns = [NSString stringWithSomething:something];
return [ns UTF8String];
}
The nature of something is not important here.
Pre-ARC rules make sure the returned data pointer will stay valid for the lifetime of current autorelease pool. Crucially, I don't carry the NSString pointer around.
Now, under ARC, won't the string be released when the function returns? I don't think ARC will consider a char * to a structure deep inside an NSString a strong reference, especially seeing that it's not explicitly freed ever.
What's the best ARC idiom here?
If you want to guarantee that the return value of UTF8String is valid until the current autorelease pool is drained, you have two options:
Define GetStringBuffer in a file that is compiled with ARC disabled. If stringWithSomething: follows convention, it must return an autoreleased NSString to a non-ARC caller. If it doesn't (e.g. it acts like -[NSArray objectAtIndex:]), you can explicitly retain and autorelease it.
Use toll-free bridging and CFAutorelease:
char *GetStringBuffer(something) {
NSString *ns = [NSString stringWithSomething:something];
CFAutorelease(CFBridgingRetain(ns));
return [ns UTF8String];
}
(I can't delete this because it's accepted, but this answer is incorrect. See Rob Mayoff's answer, and the comments on that answer for an explanation. There is no promise that this pointer is valid past the return statement.)
Rewriting my whole answer. Had to dig and dig, but I believe this is surprisingly safe today (due to improvements in ARC since I had my crashes; I knew something like that was rolling around in the back of my head). Here's why:
#property (readonly) __strong const char *UTF8String NS_RETURNS_INNER_POINTER; // Convenience to return null-terminated UTF8 representation
UTF8String is marked NS_RETURNS_INNER_POINTER, which is really objc_returns_inner_pointer. Calling that method:
the object’s lifetime will be extended until at least the earliest of:
the last use of the returned pointer, or any pointer derived from it, in the calling function or
the autorelease pool is restored to a previous state.
Which is pretty much what you wanted it to do.

Do we need to deallocate CFArray?

I have a CFMutableArray that I created using CFArrayCreateMutable.
I just need to know whether I need to deallocate this array by myself, or is it already taken care by the ARC? If I need to deallocate this, how can I, since I didn't find any function like CFArrayRelease?
All Core Foundation objects that were allocated/copied/retained by user should be released by the user. To release the CFMutableArray, you use CFRelease() function.
CFMutableArrayRef ar = CFArrayCreateMutable(kCFAllocatorDefault, capacity, NULL);
// some code
CFRelease(ar);
More information here:
https://developer.apple.com/library/ios/documentation/CoreFoundation/Conceptual/CFMemoryMgmt/Concepts/Ownership.html#//apple_ref/doc/uid/20001148-CJBEJBHH
https://developer.apple.com/library/ios/documentation/CoreFoundation/Conceptual/CFMemoryMgmt/Articles/lifecycle.html#//apple_ref/doc/uid/TP40002439-SW1
Yes, we need.
You have two options:
Transfer ownership to ARC while creating the item by casting the type to an Objective-C object.
NSMutableArray *array = (NSMutableArray *)CFBridgingRelease(CFArrayCreateMutable … )
Or release the object later
CFRelease(cfMutableArray)

iOS: Error and Crash by NSString with C malloc

Was testing some code and found an error with the following lines:
NSString *stringA = #"C99";
NSString *stringB = (__bridge id)malloc(sizeof (stringA));
It is not necessary to alloc a NSString this way, of course, and I am not required to do that. Again I was just testing on something else and I happened to stumble upon this.
The error reads:
Thread 1: EXC_BAD_ACCESS (code=1, address=0x20)
In the console:
(lldb)
To generalize, perhaps I should ask:
Could we alloc Objective-C objects through the use of malloc?
Has someone encountered this before (which I doubt, because I don't think anyone who uses Objective-C would alloc a NSString this way), but rather than shoving it aside and call it a day, I thought I would ask and see if someone knows what the exact cause of this is and why.
It is possible to use custom allocators for Objective-C objects. The problems with your code include:
NSString is a class cluster superclass (similar to an "abstract class") and cannot be instantiated on its own. You would need to use some concrete subclass of NSString. Note that the OS API does not provide any such class.
sizeof(stringA) is the size of the pointer variable, 4 or 8 bytes, which is too small to hold an NSString instance. You would need to use class_getInstanceSize() to compute the size.
+alloc performs work other than the allocation itself which is not present here. You would need to erase the memory and call objc_constructInstance().
ARC forbids the use of the low-level runtime functions that are needed to accomplish the above tasks.
well as far as I found the closest example of allocating NSSTring Clike is like this:
NSString* s4 = (NSString*)
CFStringCreateWithFormat(kCFAllocatorDefault, 0,
(CFStringRef) __builtin___CFStringMakeConstantString("%# %# (%#)"), s1, s2, s3);
ofcourse if you want to go lower and lower levels of this allocations , you should watch the CFStringRef class for its lower allocation .
but I hope this answer will satisfy you
found here, also there is more interesting things
http://www.opensource.apple.com/source/clang/clang-318.0.45/src/tools/clang/test/Analysis/NSString.m
I think the question you should be asking is what purpose that code serves.
Note that sizeof doesn't return the number of bytes in stringA, it simply returns the size of the pointer that is stringA. Who knows what lives in that little block of memory that has been allocated to stringB. Maybe it's a string, maybe not. Life is full of mystery.

Copying a block

Could some one tell me why the memory address of the localComplete block and the self.block are the same? self.complete's property is set to copy, and just to be sure i also call copy on localComplete when assigning it to self.complete.
- (void) test {
CompletionBlock localComplete = ^{
};
NSLog(#"localComplete - %p", localComplete);
self.block = [localComplete copy];
NSLog(#"self.complete - %p", self.block);
self.block();
}
Here is the output:
2013-10-05 08:39:18.549 TestApp[90703:a0b] localComplete - 0x60b8
2013-10-05 08:39:18.550 TestApp[90703:a0b] self.complete - 0x60b8
As another example I create strings:
// creating string
self.carType = [[NSString alloc] initWithFormat: #"Good%#", #"year"];
NSLog(#"self.carType - %p", self.carType);
// same memory address???
NSString *carInitString = [[NSString alloc] initWithString: self.carType];
NSLog(#"carInitString - %p", carInitString);
// same memory address???
NSString *carCopy = [self.carType copy];
NSLog(#"carCopy - %p", carCopy);
// different memory address
NSString *carInitWithFormat = [[NSString alloc] initWithFormat: #"%#", self.carType];
NSLog(#"carInitWithFormat - %p", carInitWithFormat);
And the output:
2013-10-05 09:45:01.667 TestApp[91103:a0b] self.carType - 0xa084910
2013-10-05 09:45:01.668 TestApp[91103:a0b] carInitString - 0xa084910
2013-10-05 09:45:01.668 TestApp[91103:a0b] carCopy - 0xa084910
2013-10-05 09:45:01.668 TestApp[91103:a0b] carInitWithFormat - 0xa336b70
Why isn't carInitString and carCopy different memory addresses? Optimizations are turned off in the projects build settings.
Concerning your original question, blocks are normally allocated on the stack. Copying a block (either with the Block_Copy function or the -copy method) will move the block on the stack (further calls will just increase the block's retain count)
Block_copy [...], given a block pointer, either copies the underlying block object to the heap, setting its reference count to 1 and returning the new block pointer, or (if the block object is already on the heap) increases its reference count by 1
(source)
So in your example, you may expect different addresses, since the first block is local, whereas the second one is on the heap, BUT since that specific block doesn't make any reference to the surrounding scope, the compiler will mark it as a global block. Global blocks are not allocated on the stack, and are instead at a fixed location in memory.
Copying a global block won't move the block anywhere. It will just increase its retain count, since the object is already on the heap. That's why you don't get two different addresses.
Try to make a block with a reference to the surrounding context and you will have two different addresses (stack and heap).
Now, let's address your question about NSString.
Copying an immutable object can result in a retain as an optimization (I mean, a framework design optimization, the compiler has nothing to do with it), depending on how the class implements the NSCopying protocol.
This is true for many Foundation classes like NSString, NSArray, NSSet...
This is perfectly compliant with the NSCopying protocol specification, as you can read in the documentation:
Your options for implementing this protocol are as follows:
...
Implement NSCopying by retaining the original instead of creating a new copy when the class and its contents are immutable.
As noted by Greg Parker in the comments, -[NSString initWithString:] performs the same kind of optimization. If you pass an immutable string as argument, it just retains and return the same string.
This is a useful behavior in a few situations, here's an example: you declare a property
#property (nonatomic, copy) NSArray *anArray;
and you expose it in the interface.
Declaring it as copy is a good practice in order to ensure that the object you are working on doesn't get changed by the client later on. If you just retain it and the client passes in a NSMutableArray you cannot prevent her to manipulate the object.
So copying is good, but it looks like it comes with a price: you are going to copy the object even when you don't need to (i.e. it's immutable).
Thanks to the behavior discussed above, however, you don't pay such price. Sending copy to an NSArray will just retain it, whereas sending it to a NSMutableArray will actually copy it, so in this case is a big win.
it could be because the copy isn't necessary. you don't capture any variables or anything like that. so perhaps the block is constant. try having it refer to a local or __block variable.

Exporting large amounts of data from coredata to json

I'm trying to export some data from core data to JSON. While the record count isn't particularly large (around 5000-15000 records), my data model is complex and there is a large amount of data in each record, so when I export this I exceed the allowable memory and iOS kills my app.
The steps i currently take are:
1. I have a method that extracts all the data from cordata and stores it an `NSDictionary`
2. I then write it to a file using an `NSOutputStream` and `NSJSONSerialization`
3. I then zip up the file and send it via email
I'm pretty sure that steps 2 and 3 are fine from a max memory perspective as I stream the data. But the problem is that it gets killed in step 1 because I'm effectively pulling all the data out of CD and putting it in memory so I can pass it through NSOutputStream to NSJSONSerialization.
Anyone know how to not have to pull everything into memory, but still write to a single tree JSON file?
Update - More Detail
My data structure (simplified for clarify) looks like this.
Given its not just a flat set of records but a hierarchal structure of objects with relationships i cant figure out how to pull the data out of core data in batches and fed tot he json streamer rather than all in memory to construct the json. my step one above is actually a collection of recursive methods that pull the data out of the core data entities and construct the 'NSDictionary'.
Folder {
Folder {
Word {
details type 1
details type 2
}
Word {
details type 1
details type 2
}
}
Folder {
Word {
details type 1
details type 2
}
Word {
details type 1
details type 2
}
}
Word {
details type 1
details type 2
}
}
[UPDATED TO IMPLEMENT LOW MEMORY SERIAL OUTPUT OF NESTED FOLDER HIERARCHY AS NESTED JSON OBJECT FILE]
Now you have provided more detail it's clear the original problem statement lacked sufficient detail for anyone to be able to provide an answer for you. Your issue is actually an age-old problem of how to traverse hierarchies in a memory efficient way combined with the fact the iOS JSON Library is quite light and doesn't easily support streamed writing of deep hierarchies).
The best approach is to use a technique known as the visitor pattern. For each of your NSManagedObject types shown above, implement a protocol called visitor, e.g. just the interface line for each object should look something like this:
#interface Folder : NSManagedObject <Visitable>
#interface Word : NSManagedObject <Visitable>
The visitor protocol should define a method call for all objects that comply with the protocol.
#protocol Visitable <NSObject>
- (void)acceptVisitor:(id<Visitor>)visitor;
#end
You are going to define a visitor object, which itself implements a visitor protocol.
#protocol Visitor <NSObject>
- (void)visitFolder:(Folder*)folder;
- (void)visitWord:(Word*)word;
#end
#interface JSONVisitor : NSObject <Visitor>
#property (nonatomic, strong) NSURL *streamURL;
- (void)startVisiting:(id<Visitable>)visitableObject;
#end
#implementation JSONVisitor
#property (nonatomic, strong) NSOutputStream *outputStream;
- (void)startVisiting:(id<Visitable>)visitableObject
{
if ([visitableObject respondsToSelector:#selector(acceptVisitor:)]
{
if (_outputStream == nil)
{
// more code required set up your output stream
// specifically as a JSON output stream.
// add code to either set the stream URL here,
// or set it when the visitor object is instantiated.
_outputStream = [NSOutputStream outputStreamWithURL:_streamURL append:YES];
}
[_outputStream open];
// Note 1a Bypass Apple JSON API which doesn't support
// writing of partial objects (doing so is very easy anyway).
// Write opening root object fragment text string to stream
// such as:
// {
// "$schema" : "http://myschema.com/draft-01/schema#Folder1",
// "name" : "Folder export",
// "created" : "2013-07-16T19:20:30.45+01:00",
// "Folders" : [
[visitableObject acceptVisitor:self];
// Note 1b write closing JSON root object
// e.g.
// ]
// }
[_outputStream close];
}
}
- (void)visitFolder:(Folder*)folder
{
// Note 2a Bypass Apple JSON API which doesn't appear to support
// writing of partial objects (Writing JSON is very easy anyway).
// This next step would be best done with a proper templating system,
// but for simplicity of illustration I'm suggesting writing out raw
// JSON object text fragments.
// Write opening JSON Folder object fragment text string to stream
// e.g.
// "Folder" : {
if ([folder.folders count] > 1) {
// Write opening folder array fragment to stream e.g.
// "Folders" : [
// loop through folder member NSManagedObjects here
// (note defensive checks for nulls not included).
NSUInteger count = 0;
for (Folder *nestedFolder in folder.folders)
{
if (count > 0) // print comma to output stream
[nestedFolder acceptVisitor:self];
count++;
}
// write closing folders array to stream
// ]
}
if ([folder.words count] > 1) {
// Write opening words array fragment to stream e.g.
// "Words" : [
// loop through Word member NSManagedObjects here
// (note defensive checks for nulls not included).
NSUInteger count = 0;
for (Word *nestedWord in folder.words)
{
if (count > 0) // print comma to output stream
[nestedFolder acceptVisitor:self];
count++;
}
// write closing Words array to stream
// ]
}
// Print closing Folder object brace to stream (should only be followed
// a comma if there are more members in the folder this object is contained by)
// e.g.
// },
// Note 2b Next object determination code here.
}
- (void)visitWord:(Word*)word
{
// Write to JSON stream
[NSJSONSerialization writeJSONObject:word toStream:_outputStream options: NSJSONWritingPrettyPrinted error:nil];
}
#end
This object is able to "visit" each object in your hierarchy and do some work work with it (in your case write it to a JSON stream). Note you don't need to extract to a dictionary first. You just work directly with the Core Data objects, making them visitable. Core Data contains it's own memory management, with faulting, so you don't have to worry about excessive memory usage.
This is the process. You instantiate the visitor object and then call it's start visiting method passing in the root Folder object of your hierarchy above. In that method, the visitor object "knocks on the door" of the first object to be visited by calling - (void)acceptVisitor:(id<Visitor>)visitor on the object to be visited. The root Folder then "welcomes the visitor in" by calling a method back on the visitor object matching it's own object type, e.g.:
- (void)acceptVisitor:(id<Visitor>)visitor
{
if ([visitor respondsToSelector:#selector(visitFolder:)]) {
[visitor visitFolder:self];
}
}
This in turn calls the visitFolder: method on the visitor object which opens the stream writes the object as JSON and closes the stream. This is the important thing. This pattern may appear complex at first, but I guarantee, if you are working with hierarchies, once you have implemented it you will find it powerful and easy to manage.
To support low memory serial output of a deep hierarchy, I'm suggesting you write your own JSON Folder object to the output stream. Since JSON is so simple, this is much easier than it might at first appear. The alternative is to look for a JSON Library which supports low memory serialised writing of nested objects (I haven't used JSON much so don't know if such exists and is easy to use on iOS). The visitor pattern ensures you need have no more than one NSManagedObject instantiated to work on for each level of the hierarchy (though of course more will inevitably need to be instantiated as you implement hierarchy traversal logic) so this is light on memory usage.
I have given examples of the text string that needs to be written to the output stream. Best practice would dictate using a templating system for this rather than directly writing statically allocated strings. But personally I wouldn't worry about adopting the quick and dirty approach if your deadline is tight.
I've assumed your folder objects contain a folders property providing a set of additional folders. I have also assumed your Folders NSManagedObject class contains a words property containing a set of Words NSManagedObjects. Remember if you stay working in Core Data it will look after ensuring you keep a low memory footprint.
At the end of the visitFolder: method, you can use the following logic.
Check if the Folder's contains any folders and visit each in turn if it does.
If it contains no more folders, check if it contains any Words, and visit each in turn if it does.
Note the above code is the simplest construct for minimising the memory footprint. You may want to optimise it for performance by e.g. only doing an auto-release when a certain batch size is exceeded. However given the problem you have described, it will be best to implement the most memory efficient method first.
If you have polymorphic hierarchies - your on your own :) - get a book out and do some study -managing them is a grad degree in itself.
Clearly this code is untested!
Check the NSFetchRequest documentation. You will see two properties:
- (NSUInteger)fetchOffset;
– fetchBatchSize;
With use of these two properties you can restrict the number of returned NSManagedObjects to a given batch size.
Open a stream you can write too. Set up a loop to execute a fetch request. But set a batch size (x) and then update the fetch offset of the fetch request at the end of the loop code for the next iteration of the loop.
myFetchRequestObject.fetchOffset += x;
Process the batch of data objects writing the JSON data to your open stream before starting the next iteration of the loop.
When either no more objects are returned or the number of objects returned by the fetch are less than the batch size, exit your loop.
Close your stream.
problem was that i had Enable Zombie Objects in the project schema turned on.
For some reason this also carried through to the release build too.
turning it off fixed all my problems.
I ended up also using TheBasicMinds design pattern because its a cool design pattern...

Resources