美文网首页
OC对象的本质

OC对象的本质

作者: 冰棍儿好烫嘴 | 来源:发表于2023-03-14 21:11 被阅读0次

我们平时编写的Objective-C代码,底层实现其实都是C/C++代码


所以Objective-C的面向对象都是基于C/C++的数据结构实现的。
Objective-C的对象、类是基于C/C++的结构体数据结构实现的。
将Objective-C代码转换为C/C++代码(需要用到clang编译器)
在终端一直cd到想要转为cpp文件的所在位置,然后敲命令行

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

将main.m文件转为main.cpp文件,因为平台不同支持的代码肯定不一样,例:windows、Mac、iOS等,这里主要讨论iOS平台,所以用如下命令行

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

NSObject的底层实现


Class isa里边的Class是一个指向结构体的指针。

runtime里边有一个获取实例实际大小的方法,如下

#import <objc/runtime.h>
NSObject *obj = [[NSObject alloc] init];
//获得NSObject实例对象的成员变量所占用的大小 >> 8
num = class_getInstanceSize([NSObject class]);
NSLog(@"%zd",num);//无符号的打印方式
打印结果为8

malloc里边有一个获取开辟内存大小的方法,如下

#import <malloc/malloc.h>
NSObject *obj = [[NSObject alloc] init];
//获得obj指针所指向内存的大小>>16
num = malloc_size((__bridge const void *)obj);
NSLog(@"%zd",num);
打印结果为16

opensource源码下载

一个NSObject对象占用多少内存?

系统分配了16个字节给NSObject对象(通过malloc_size函数获得),但NSObject对象内部只使用了8个字节的空间(64bit环境下,可以通过class_getInstanceSize函数获得)

NSObject *obj = [[NSObject alloc] init];
下断点,然后实时查看内存数据

实时查看内存数据方法:
Debug-> Debug Workflow -> View Memory (Shift + Command + M)

也可用lldb指令查看内存:
常用lldb指令
print、p:打印
po:打印对象

  • 读取内存:
    memory read/数量格式字节数 内存地址
    x/数量格式字节数 内存地址

  • 修改内存中的值
    memory write 内存地址 数值
    memory write 0x0000010 10

  • 格式
    x是16进制,f是浮点,d是10进制

  • 字节大小
    b:byte 1字节,h:half word 2字节
    w:word 4字节,g:giant word 8字节




现在研究一下自定义的对象(有新的成员属性)占用的内存
在main.m文件中新建一个继承NSObject的Student类,然后写两个int类型的成员变量,再把main.m文件转成c++文件

@interface Student : NSObject
{
    @public
    int _no;
    int _age;
}
@end
@implementation Student
@end
Student *student = [[Student alloc] init];

xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main.cpp
在cpp文件中发现

struct NSObject_IMPL{
    Class isa;
}
struct Student_IMPL{
    struct NSObject_IMPL NSObject_IVARS;
    int _no;
    int _age;
};
Student *student = [[Student alloc] init];
student->_no = 4;
student->_age = 5;
        
NSLog(@"%zd",class_getInstanceSize([Student class]));//16
NSLog(@"%zd",malloc_size((__bridge  const void *)student));//16

再用实时查看内存数据的方法去查看,先在lldb中打印出student的首地址,p student,然后把对象的首地址在debug -> debug workflow -> view memory中显示内存数据。如下图:

大端小端模式:

思考:一个Person对象、一个Student对象占用多少内存空间?

@interface Person : NSObject
{
    @public
    int _age;
}
@end
@implementation Person
@end

@interface Student : Person{
    @public
    int _no;
}
@end
@implementation Student
@end

Person *person = [[Person alloc] init];
Student *stu = [[Student alloc] init];
        
NSLog(@"Person -- %zd",class_getInstanceSize([Person class]));//16  class_getInstanceSize内存对齐过的占用的大小
NSLog(@"Person -- %zd",malloc_size((__bridge  const void *)person));//16
NSLog(@"Student -- %zd",class_getInstanceSize([Student class]));//16
NSLog(@"Student -- %zd",malloc_size((__bridge  const void *)stu));//16

方法不在实例对象内存里边,所以方法不占用内存,只有成员变量和属性影响内存的大小。方法放在什么地方???(后边研究再补充:类对象的方法列表里边)

2个容易混淆的函数

  • 创建一个实例对象,至少需要多少内存?
#import <objc/runtime.h>
class_getInstanceSize([NSObject class])
  • 创建一个实例对象,实际上分配了多少内存?
#import <malloc/malloc.h>
malloc_size((__bridge  const void *)obj);

相关文章

网友评论

      本文标题:OC对象的本质

      本文链接:https://www.haomeiwen.com/subject/nwckrdtx.html