Let’s start with an interview question:

Interview question: How much memory does an NSObject take up?

As an iOS developer, although the underlying principles of iOS are more often asked in interviews, but in practical work, the underlying principles of iOS is a must to master the knowledge. To understand the underlying principles of iOS, it’s important to understand the following two things:

  • How are OC objects laid out in memory?
  • What does an OC object contain?

The memory layout of NSObject objects

The underlying implementation of objective-C code, OC code, is C/C++ code. The compiler converts OC code into C/C++ code, then into assembly language, then into machine language and finally runs on the phone. So OC code is essentially C/C++ code;

Next, explore the nature of OC objects by creating OC projects and converting OC files into C++ files.

#import "ViewController.h" @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super  viewDidLoad]; NSObject *isa_obj= [[NSObject alloc] init]; } @endCopy the code

Converting the OC viewcontroller.m file to a C++ file can be done using the following two command lines.

  • The first way is to convert to C++ without specifying a schema

    clang -rewrite-objc main.m -o main.cpp

    Where CPP stands for C++ (C plus plus)

  • The second way is to specify architectural patterns (currently arm64 for iOS) to convert to C++.

    xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc ViewController.m -o ViewController-arm64.cpp

A global search for NSObjcet_IMPL in the viewController-arm64.cpp file will find the implementation code for NSObject.

    struct NSObject_IMPL {
         Class isa;
    };

    点击Class,我们发现,Class是一个指向结构体的指针,如下:
    typedef struct objc_class *Class;
Copy the code

As you can see above, the underlying NSObject object is a C++ based implementation of data types. This data type is a structure type. Let’s print out NSObject memory, just to see how much NSObject takes up in memory

#import "ViewController.h" #import <objc/runtime.h> #import <malloc/malloc.h> @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; NSObject *isa_obj= [[NSObject alloc] init]; NSLog(@"%zd",class_getInstanceSize([NSObject class])); NSLog(@"%zd",malloc_size((__bridge const void *)isa_obj)); }Copy the code

The output

2018-10-10 15:42:53.776715+0800 NSObject essential-01 [5132:224858] 2018-10-10 15:42:53.776875+0800 NSObject essential-01 [5132:224858] 2018-10-10 15:42:53.776875+0800 NSObject essential-01 [5132:224858] 16Copy the code

According to the print, the pointer to the NSObject object takes up 8 bytes, but the NSObject object takes up 16 bytes. In fact, class_getInstanceSize returns the size of the member variable, which in the example above is just an ISA pointer. Malloc_size returns the size of the NSObject object in memory.

Back to the interview question at the beginning

Interview question: How much memory does an NSObject take up? The object orientation of NSObject is implemented as a C/C++ data type, which is a structure. In the NSObject header file, Class is a pointer to a structure. In 64-bit environments, Pointers occupy 8 bytes. But the system actually assigns 16 bytes to the NSObject object. But the NSObject takes up 8 bytes internally.

During the initialization of NSObject, the NSObject object is allocated 16 bytes of memory, of which 8 bytes are used to hold a member ISA pointer. The address of the isa pointer variable is the address of the structure, that is, the address of the NSObjcet object. Assuming the address of ISA is 0x100400110, the system allocates storage space to the NSObject object and then assigns the address of storage space to the objC pointer. Objc stores the address of isa. Objc points to the NSObject object address in memory, that is, to the structure in memory, the isa location.

We illustrate the internal layout with custom classes

#import <Foundation/Foundation.h>

@interface Student : NSObject
{
    @public
    int _no;
    int _age;
}
@end

@implementation Student


@end
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Student *student = [[Student alloc] init];
        student -> _no = 1;
        student -> _age = 18;
    }
    return 0;
}
Copy the code

Generate c++ file by following the above c++ generation steps and find Student, c++ file as follows:

struct Student_IMPL {
    struct NSObject_IMPL NSObject_IVARS;
    int _no;
    int _age;
};
Copy the code

We find the NSObject_IMPL implementation by searching for NSObject_IMPL

struct NSObject_IMPL {
    Class isa;
};
Copy the code

So the structure of Student_IMPL is equivalent to

struct Student_IMPL {
    Class *isa;
    int _no;
    int _age;
};
Copy the code

Therefore, the Student object takes up as much storage space as the structure takes up. The storage space occupied by the structure is: ISA pointer (8 bytes) +int _NO (4 bytes) +int _age (4 bytes) = 16 bytes

The contents of the OC object

OC objects can be divided into three types: 1. Instance objects 2. Class objects 3. Meta-class objects

1. Instance

An instance object is an object that comes out of the class alloc, and every time you call that alloc, you create a new instance object; Instance objects store information in memory including:

  • Isa pointer
  • Specific values of other member variables

2, class object

Objects using class (class objects) Each class has only one class object in memory

Note: The class method always returns a class object, so this will still return a class object

Class objectMetaClass2 = [[[NSObject class] class] class];

The class object stores information in memory:

  • Isa pointer
  • Superclass pointer
  • Class property information (@property), class object method information (instance method)
  • Class protocol information (Protocol), class member variable information (IVAR)
  • .

3. Meta-class

ObjectMetaClass is a meta-class object of NSObject. Each class has one and only one meta-class object in memory

Class objectMetaClass = object_getClass(objectClass5);

Meta-class objects have the same memory structure as class objects, but their purpose is different. They store the following information:

  • Isa pointer
  • Superclass pointer
  • Class method information of a class
  • .

The pointer to isa

  • Instance isa points to class

When an object method is called, the class is found through the ISA pointer to the instance object, and finally the implementation of the object method is found.

  • The ISA pointer to class points to meta-class

When a class method is called, the meta-class is found through the class isa, and the implementation of the class method is finally found to call.

Superclass pointer to the class object

  • When a Student instance calls a Person object method, it finds Student’s superclass through ISA, then finds Person’s class through superclass, and finally finds the implementation of the object method

Superclass pointer to a meta-class object

  • When a Student class calls a Person class method, Student’s meta-class is first identified by ISA, then Person’s meta-class is identified by superclass, and finally the implementation of the class method is identified.

Isa, superclass summary

  • Instance isa points to class
  • Class’s ISA points to meta-class
  • The ISA of the meta-class points to the meta-class of the base class
  • The superclass of class refers to the superclass of the parent class; If there is no superclass, the pointer to superclass is nil
  • The superclass of the meta-class points to the meta-class of the superclass; The superclass of the meta-class of the base class points to the class of the base class
  • Instance calls the path of an object’s method; Superclass = superclass; superclass = superclass
  • Class calls the class method trace; Superclass = superclass; superclass = superclass

Reprinted from Jane’s Book