手把手带你去分析NSObject本质是什么

请添加图片描述

✅作者简介:大家好我是瓜子三百克,一个非科班出身的技术程序员,还是喜欢在学习和开发中记录笔记的博主小白!
📃个人主页:瓜子三百克的主页
🔥系列专栏:OC语法
💖如果觉得博主的文章还不错的话,请点赞👍+收藏⭐️+留言📝支持一下博主哦🤞
作者请求:由于博主水平有限,难免会有错误和不准之处,希望各位小伙伴能够在留言区批评斧正。


这篇行文主要讲 NSObject 对象三连问:NSObject本质是什么,占用多少内存,以及怎么去分析。
从下图我们可以看到,我们平时编写的 Objective-C 代码,最终转换到机器语言的过程:
在这里插入图片描述换句话说,Objective-C的面向对象都是基于C\C++的数据结构实现的,或者说其底层实现其实都是C\C++代码。

为了看清 Objective-C 的本质,我们先了解下如下将 Objective-C 代码转换为 C\C++ 代码。

一、代码转换

1、 添加 NSObject 对象

如在 main.m 添加一个 NSObject 对象(或者直接复制以下代码到 main.m 文件中):

#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#import <malloc/malloc.h>

int main(int argc, char * argv[]) {
    @autoreleasepool {
        NSObject *obj = [[NSObject alloc] init];
    }
    return 0;
}

2、命令行实现

已知:
1、不同平台支持的代码是不一样的( Windows、mac、iOS)
2、iOS架构:模拟器(i386)、32bit(armv7)、64bit(arm64)

命令行格式如下:

// 不指定平台和架构
clang -rewrite-objc main.m -o main.cpp

// 指定真机(ios平台64bit架构)
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main-arm64.cpp
// 指定模拟器
xcrun -sdk iphonesimulator clang -arch i386 -rewrite-objc  main.m -o main-i386-simulator.cpp


// 命令行格式
// xcrun:xcode run
// -sdk 平台:iphoneos
// -arch 架构:arm64
// -rewrite-objc:重写OC
// main.m -o main-arm64-1.cpp:OC源文件  -o  输出的CPP文件
// 如果需要链接其他框架,使用-framework参数。比如-framework UIKit
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main-arm64.cpp

执行生成目录:

chenzimin@rattanchen InterView % tree
.
├── Info.plist
├── main-arm64-iphoneos.cpp
├── main-i386-simulator.cpp
├── main.cpp
└── main.m

0 directories, 5 files

3、结果

main 方法中转化的代码依次如下:
1、不指定机型架构:
在这里插入图片描述
2、指定机型架构:在这里插入图片描述以上直观的感知转cpp的代码是一样的,但是不配置机型机构的部分,因为需要涉及兼容问题,代码行数相差了将近三倍。所以按机型配置可以节省很多存储空间。

二、本质分析

看到OC实现和 C\C++ 底层实现,如下:
在这里插入图片描述结论:
1、NSObject 对象在内存中就是一个结构体(结构体优势:可以兼容不同种数据类型)。

在这里插入图片描述2、Class:是指向结构体的指针。
3、指针占位大小:64位环境占8个字节(下面默认按64位系统计算),32位环境占4个字节。
4、而 NSObject_IMPL 只有一个成员对象,那么 isa 成员的地址就是结构体在内存中的地址,占8个字节。

NSObject *obj = [[NSObject alloc] init]; 代码解读:

// 1、创建好一个对象并给这个对象分配内存地址,假设地址为:0x100400110
[[NSObject alloc] init];

// 2、设置一个指针 *obj
NSObject *obj;

// 3、让 *obj 指针指向/存储这个对象的内存地址。
NSObject *obj = [[NSObject alloc] init];

图如下:
在这里插入图片描述

三、NSObject 是有多少内存呢?

继续以上例子,已知有两个方法可以获取内存分配空间:

#import <objc/runtime.h>
#import <malloc/malloc.h>

// 获得NSObject实例对象的成员变量所占用的大小 >> 8
NSLog(@"%zd", class_getInstanceSize([NSObject class]));

// 获得obj指针所指向内存的大小 >> 16
NSLog(@"%zd", malloc_size((__bridge const void *)obj));

为什么一个返回8字节,另一个返回16字节。注意了,它们虽然都是获取占用内存大小。但是获取对象不一样。

  • class_getInstanceSize 方法获取的是实例对象的成员变量所占用的大小。
  • malloc_size 获取的是指针所指向的内存大小。

那为什么指针所指向的内存会更大呢?这时可以查看一下OC底层原码是如何分配内存的,如下:

    size_t instanceSize(size_t extraBytes) {
        size_t size = alignedInstanceSize() + extraBytes;
        // CF requires all objects be at least 16 bytes.
        if (size < 16) size = 16;
        return size;
    }

可以看到,当分配内存小于16位时,直接设置16,这是他们底层的规定。

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

四、Demo

InterView-NSObject的内存分析



**🏆结束语🏆 **

最后如果觉得我写的文章对您有帮助的话,欢迎点赞✌,收藏✌,加关注✌哦,谢谢谢谢!!

  • 6
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

瓜子三百克

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值