If I make my object a subclass of UIViewController, does it use substantially more memory than if it is a subclass of NSObject? A ballpark figure for how much more overhead is used by subclassing a complex class vs a simple one would be great. edit: or a way to figure out the difference myself.
You can imagine that an objective-c object is just a C structure that looks like this:
typedef struct {
Class isa;
} NSObject;
An instance of that structure would take 4 bytes on a 32-bit system. Since it's composed of a single pointer - Class is similar to id.
A subclass of NSObject, MySubclass with one 'char' instance variable would look like this:
typedef struct {
Class isa;
char singleInstanceVariable.
} MySubclass;
A subclass simply has all of the instance variables of its super class at the beginning, plus its own at the end. You can see this in the debugger by typing 'p *object' in the console.
MySubclass's size would be 5 bytes on a 32-bit system. One pointer, plus one char. So, an object's size is the size of all of it's instance variables added together. One important thing to know is that an object's size is only related to its instance variables. It isn't impacted by the number of methods it has. Those methods don't cost any extra memory as more instances are instantiated. Methods have a fixed initial cost.
Another thing to consider is that objects usually have pointers to other objects as instance variables. For example, let's say every UIView has an NSMutableArray to reference its subviews. That array might be 12 bytes when empty. So an empty UIView would be the size of all of the variables in a UIView, which would include 4 bytes for the pointer to an array, plus you might also account for the 12 additional bytes used by the actual array instance. That's all just accounting though, the array and the view are two distinct objects, but the view isn't really usable without the array.
Lastly, most allocations are rounded up to some quantum in order to make the malloc implementation faster and to satisfy some constraints of the architecture of the machine so that pointers are properly aligned. Also an object's instance variables might have empty padding in between them similar to structure padding
That depends on the number and nature of the superclass's instance variables. NSObject has one ivar, the isa pointer. UIViewController has about 30 ivars, most of them pointers (you can look the list up in UIViewController.h).
So any subclass of UIViewController will take up as much memory as is needed to store all those ivars and all ivars of its superclasses (UIResponder (no ivars) and NSObject (one ivar)).
This calculation does not take into account the actual memory that is used by the objects these instance variables reference when initialized, of course. For example, a fully initialized view controller may hold on to a view object that takes up a considerable amount of memory.
Try class_getInstanceSize([MyClass class]);. Roughly speaking, the memory usage of an instance will be this value rounded up to a multiple of sixteen bytes. Of course, this doesn’t include overhead of any associated objects (see objc_setAssociatedObject) or allocations the class makes.
In short, yes, but probably not enough that you need to worry about it unless you're planning on instantiating tens thousands of them.
The object will allocate memory for each of its ivars and its methods. The amount of memory needed depends on the C types... they all vary according to the datatype what's being stored.
The amount of memory used depends on how the object is instantiated, presented on screen, and interacted with. For example, a subclass of NSObject will not have any interaction with the user's touches.
You can always attach you application with the Instruments Allocations performance tool to compare the difference.
Related
All classes in objective-C inherited from objc_class, which has superClass, cache_t and class_data_bits containing all the methods, properties and protocols.
A instance object stores its superClass, methods, properties and protools informations in its class object, and class object stores its information in metaClass's class_data_bits.
So what else an instance object stores besides an isa pointer since all the class information has been stored in its class object?
The object's data.
ObjC objects are laid out as a header, followed by instance variables (first the root class, then each subclass down to the object's direct instance variables). You won't see this anywhere directly in objc_object. But you'll see it in _class_createInstancesFromZone:
size_t size = cls->instanceSize(extraBytes);
num_allocated =
malloc_zone_batch_malloc((malloc_zone_t *)(zone ? zone : malloc_default_zone()),
size, (void**)results, num_requested);
Note the call to cls->instanceSize(extraBytes). This is the full size of the instance, including its ivars (plus "extra"). It allocates much more than just an isa pointer. The Ivar table has offsets into that additional allocation.
The "extra" is not used very often, but it allows you to allocate extra memory for whatever purpose you like. For example, NSString allocates extra inline storage for its data rather than creating an extra pointer indirection. (I assume it still does this; it used to, but I haven't checked the code in a while.)
I know that when an object is instantiated on the heap, at the least enough memory is allocated to hold the object's ivars. My question is about how methods are stored by the compiler. Is there only one instance of method code in memory? Or is the code generated an intrinsic part of the object in memory, stored contiguously with the ivars and executed?
It seems like if the latter were the case, even trivial objects such as NSStrings would require a (relatively) large amount of memory (NSString inherits methods from NSObject, also).
Or is the method stored once in memory and passed a pointer to the object which owns it?
In a "standard" Objective-C runtime, every object contains, before any other instance variables, a pointer to the class it is a member of, as if the base Object class had an instance variable called:
Class isa;
Each object of a given class shares the same isa pointer.
The class contains a number of elements, including a pointer to the parent class, as well as an array of method lists. These methods are the ones implemented on this class specifically.
struct objc_class {
Class super_class;
...
struct objc_method_list **methodLists;
...
};
These method lists each contain an array of methods:
struct objc_method_list {
int method_count;
struct objc_method method_list[];
};
struct objc_method {
SEL method_name;
char *method_types;
IMP method_imp;
};
The IMP type here is a function pointer. It points to the (single) location in memory where the implementation of the method is stored, just like any other code.
A note: What I'm describing here is, in effect, the ObjC 1.0 runtime. The current version doesn't store classes and objects quite like this; it does a number of complicated, clever things to make method calls even faster. But what I'm describing still is still the spirit of how it works, if not the exact way it does.
I've also left out a few fields in some of these structures which just confused the situation (e.g, backwards compatibility and/or padding). Read the real headers if you want to see all the gory details.
Methods are stored once in memory. Depending on the platform, they are paged into RAM as needed. If you really want more details, read the Mach-O and runtime guides from Apple. It's not usually something programmers concern themselves with any more unless they're doing something pretty low-level.
Objects don't really "own" methods. I suppose you could think of it as classes owning methods, so if you have 400 NSStrings you still only have one copy of each method in RAM.
When a method gets called, the first parameter is the object pointer, self. That's how a method knows where the data is that it needs to operate on.
I have a basic question about subclassing a class with objects:
#interface Myclass : NSObject{
UIImage *image;
NSString *string;
ParticleSystem *system;
Object *obj;
Object2 *obj2;
}
If I subclass this MyClass class, and I initialise only a few of these objects defined in the superclasses header, what happens to all the other unallocated definitions in terms of memory?
The reason I ask, I have a class with many, many definitions and i've been subclassing it for simplicity sake, but my subclass only needs a fraction of these definitions.
Is it worth just subclassing NSObject and redefining the needed variables rather than subclassing MyObject?
Thanks,
Oliver.
They take up space, but only a pointer's worth (4 bytes on the iPhone) per variable.
The better reason for separating these out into separate classes is that it sounds like you don't have a very clean division of responsibilities. A class should be composed of some logical grouping of data and operations on that data. Things not having to do with the class's role probably belong elsewhere.
Each of those variables is a pointer so they are taking up the storage required to point to a memory address. (4 bytes on iPhone)
Is iPhone OS 64 bit or 32 bit?
If each of the sub classes only needs a small subset, then only include those in the base class (rather than copying and redefining in those in every class). If some of those subclasses require the full set, then you can also have a class hierarchy (layered sub-classes). It's impossible to know without seeing the concrete design.
If you just have pointers in the class definition (eg, SomeClassName* somePointerName;) then each pointer takes up one pointer location in each of your objects (4 bytes on iPhone).
Though it's occasionally convenient to do what you're doing, you're missing out on many of the benefits of object-oriented programming -- you're basically just making use of Objective-C's storage management while coding cruddy C.
I'm developing an iPhone 3.1.3 application.
I have a class, called Object2D, with fields and methods; which represent a shape. Object2D has a field that represents its size, and another field that represent its type.
Now, I need another class called Pattern, which is a set of shapes. In Pattern I'm going to have an array of shapes. From these shapes I only need their size, their type and their location inside pattern, I don't need any method.
I'm wondering it is better to have a new struct that represent a shape instead of using Object2D class.
I ask this because I think on memory performance. I'm not sure, but struct are smaller than classes and maybe it's better to use them instead of classes.
What do you think?
If you're looking at memory use, the difference is truly negligible in almost every situation. Objects are one pointer bigger than an equivalent struct.
The greater difference is in how you can use them. Objects can have methods and hierarchies and interact with the rest of Cocoa. With structs, you need to make custom functions for each struct type or hack together a pseudo-object system. On top of that, arbitrary structs don't interact well with the rest of Cocoa (Touch). For example:
If you store objects in them, you have to be very careful to do your own memory management correctly
You can't store them in NSArrays without creating an object wrapper (since NSArray is an array of objects)
You can't hook structs up in Interface Builder — it doesn't know anything about them
You can't do KVO or KVC with structs
In general, if you're working with a Cocoa-like framework, objects are a good default choice. Use structs once you've decided you really need them.
Objective-C classes are in fact structs, and, provided the instance variables are laid out in the same order as the structure members are, the only difference in size is the 4 or 8 bytes of NSObject's isa variable.
NOTE: the answer above assumes the legacy Objective-C runtime, without the use of #property and #synthesize directives, which could potentially affect their size.
I am changing the class of some objects using object_setClass(id object, Class cls). I am changing the class to a subclass of the original class. Then I set some properties that are only defined on the subclass, and things seem to work fine.
I was a bit surprised that this worked, because object_setClass, as far as I understand, doesn't reallocate the object, it only changes the isa pointer. If the subclass instances are considerably larger (meaning having many more ivars) than the original class instances, I don't see how the object can work as expected.
Does this work only because there is a lot of buffer memory between objects in memory (due to alignment etc)?
Is this robust, or could it crash under some circumstances?
It could crash. As can be seen in the source code of the runtime here, it really just swaps the isa pointer.
If you really want to swap the isa to an isa of a subclass with more ivars, you should use class_createInstance with nonzero extraBytes.
Instead of using a larger subclass, use objc_setAssociatedObject and objc_getAssociatedObject to attach dynamically additional objects to your existing fixed-size object.