一个对象至少占几个字节?

如题所示

一个对象至少占几个字节呢?

我们分别使用sizeof、class_getInstanceSize、malloc_size三个函数方法进行操作:

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

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSObject *obj = [[NSObject alloc] init];
        
        NSLog(@"obj_sizeof - %d", sizeof(obj));
        NSLog(@"obj_class_getInstanceSize - %d", class_getInstanceSize([NSObject class]));
        NSLog(@"obj_malloc_size - %d", malloc_size((__bridge const void *)(obj)));
    }
    return 0;
}

打印结果为:

2019-04-01 15:33:26.457385+0800 01-内存分析[5294:290097] obj_sizeof - 8
2019-04-01 15:33:26.457619+0800 01-内存分析[5294:290097] obj_class_getInstanceSize - 8
2019-04-01 15:33:26.457651+0800 01-内存分析[5294:290097] obj_malloc_size - 16

可以看出,sizeof、class_getInstanceSize返回的obj占8个字节,malloc_size返回obj占16个字节。

那么,为什么打印出结果不一样呢?它们都是什么意思呢?

首先,sizeof(A)不是函数,而是编译器特性,是一个运算符,在编译期间就可以确定A类型所占的字节大小。由于我们放入的是obj对象,而obj是一个指向对象的指针,因此,sizeof返回的8是obj指针所占的字节大小。而如果放入的是[NSObject class],返回什么呢?为什么呢?

class_getInstanceSize的底层究竟是什么呢?
点击进去在runtime.h文件中发现class_getInstanceSize的定义为:
在这里插入图片描述
好吧,好像什么也看不出来,那么只能通过底层开源代码查看class_getInstanceSize的实现方式了。那么

如何获取苹果底层开源代码呢?

可以通过苹果开源代码,点击objc4文件夹,下载最新的objc4-xxx.tar.gz,解压后打开项目,在项目里面搜索class_getInstanceSize,可以在objc-class.mm文件中看到:
在这里插入图片描述

alignedInstanceSize

点击alignedInstanceSize()可以看到:
在这里插入图片描述
返回的是一个类Class的一个成员变量ivar的大小。
因此,可以看出class_getInstanceSize返回的是一个类中成员变量所占的大小


malloc_size

点击malloc_size,进入可以看到如下代码:
在这里插入图片描述
可以看出,malloc_size通过输入一个指针ptr,可以返回指针所指向的内容的大小,malloc_size返回结果是一个对象实际分配的空间大小

由此可见:

一个对象obj分配了16个字节,通过《iOS中类、对象的本质》可知,一个对象obj中包含一个Class类型的指针isa,而根据《一个指针占几个字节?原理是什么呢?》可知,一个指针占8个字节(在64位电脑上),也就是Class类型的isa指针所占的8个字节大小。

那么,为什么一个对象分配了16个字节,对象只用了8个字节呢?

我们知道NSObject *obj = [[NSObject alloc] init];中alloc其实是调用的是+ (instancetype)allocWithZone:(struct _NSZone *)zone;方法,而通过上面我们下周的底层开源代码可以发现allocWithZone调用的是:
在这里插入图片描述继续点击,可以发现_objc_rootAllocWithZone的实现:
在这里插入图片描述在这里面有一个class_createInstance函数,点击进入:
在这里插入图片描述
再次点击_class_createInstanceFromZone进入:
在这里插入图片描述里面有一个obj = (id)calloc(1, size);函数,是创建obj的,而size是由size_t size = cls->instanceSize(extraBytes);返回的。点击instanceSize进入可以发现:
在这里插入图片描述这里面规定了if (size < 16) size = 16;即,如果分配的size小于16,那么就让size=16。也就是,一个对象至少分配16个字节。

另外,我们也可以通过查看obj的内存地址,通过内存地址找到所占用的二进制,查看obj到底是占用几个字节

通过打断点,我们可以找到obj的内存地址0x102800930,在Debug-Debug Workflow -View Memory
在这里插入图片描述
把内存0x102800930填写在下列框中:
在这里插入图片描述
可以看到其二进制内容:
41 61 88 9C FF FF 1D 00 00 00 00 00 00 00 00 00
该二进制是用16进制表示的,也就是一个数字是4个2进制,两个数字整好是8个二进制,也就是一个字节。通过观察可以看出,该二进制共有16个字节,但是,只有8个字节有内容,存放obj的内容,其余8个字节虽然分配了,但是并没有使用。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值