美文网首页
对象size那点事(二)

对象size那点事(二)

作者: 会跑的鱼_09 | 来源:发表于2020-09-09 14:06 被阅读0次

背景

在上篇对象alloc那点事中遗留了一个对象带有基础类型属性后占用内存大小的问题。另外参考之前分析的对象开辟内存的调用过程如下:

//确认创建类需要开辟的内存大小
size = cls->instanceSize(extraBytes);
//开辟内存
obj = (id)calloc(1, size);
//把isa信息填充到上面申请到的内存中
obj->initInstanceIsa(cls, hasCxxDtor);

开辟内存的calloc方法需要传入的size非常关键,这个size是通过instanceSize计算得出的,而分析 instanceSize 流程发现,它是拿对象的 实际占用大小 进行16字节对齐后得到 实际分配大小
所以关键问题就到了如何计算 实际占用大小 !大家知道OC类经过编译后会生成相应的结构体,所以想知道OC对象的 实际占用大小 其实就是研究结构体对象在内存中分布以及对齐方式

一、OC类示例

前面提到对象的 实际占用大小实际分配大小,这两者有什么区别呢,先看一个例子:

OC对象实际占用和分配大小
  • 实际占用大小40:8(isa) + 8(name) + 8(nickName) + 4(int) + 8(double) + 1(c1) + 1(c1) = 38,那为什么打印出来是40呢,那是因为结构体对象在底层需求经过字节对齐
  • 实际分配大小48:40再按16字节对齐(苹果的特性,所有对象最后都按16字节对齐),就是48。

二、结构体字节对齐

1.结构体对齐的原则

结构体对象在进行字节对齐时会遵从以下三点原则:

  • 数据成员 : 结构体中第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小或者成员的子成员大小(只要该成员有子成员,比如说是数组,结构体等)的整数倍开始。
  • 结构体作为成员 : 如果一个结构里有某些结构体成员,则结构体成员要从
    其内部最大元素大小的整数倍地址开始存储(struct a里存有struct b,b
    里有char、int 、double等元素,那b应该从8的整数倍开始存储)。
  • 结构体整体对齐 : 结构体的总大小,也就是sizeof的结果,必须是其内部最大 成员的整数倍,不足的要补⻬。

2.结构体对齐举例

结构体字节对齐

关键点有两个:

  • 下一个成员存储的开始位置判断,它必须是该成员自身长度的倍数。
  • 最后的收尾,必须是最大成员长度整数倍。

3.嵌套结构体对齐举例

嵌套结构体
  • 先计算LGStruct2中a、b、c、d起始位置和大小,共16字节。
  • str1开始位置的index为16,是其内部最大成员double的整数位,所以开始位置不变。
  • LGStruct1的大小为24(同样的计算逻辑),从index16开始24个字节存str1。
  • 总大小为16+24 = 40,再看是否最大成员的整数倍(这里要把被嵌套的结构体成员一起平铺来看)
再来个复杂点的
嵌套结构体

三、再看OC类

1.编译器优化

不知道大家发现没有,上面结构体对齐举例中单个LGStruct1和LGStruct2它们只是int和char的位置不同,但求出来的sizeof却不一样。如果真的都24字节来开辟内存,那对系统来说当然是一种浪费,所以在系统底层会对结构体成员进行优化,减小其开辟内存的大小。

不多解释了,注释已经很清楚

2.看一下OC类的大小

定义一个LGPerson类
@interface LGPerson : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *nickName;
@property (nonatomic, assign) double height;
@property (nonatomic) char char1;
@property (nonatomic, assign) int age;
@property (nonatomic) short shot1;
@end
OC对象

class_getInstanceSize : 获取oc类在底层对应结构体的实际占用内存大小
malloc_size : 获取系统层面对该对象实际分配的内存大小

class_getInstanceSize分析

先看一下class_getInstanceSize源码

size_t class_getInstanceSize(Class cls)
{
    if (!cls) return 0;
    return cls->alignedInstanceSize();
}
 uint32_t alignedInstanceSize() const {
    return word_align(unalignedInstanceSize());
}
static inline size_t word_align(size_t x) {
    return (x + WORD_MASK) & ~WORD_MASK;
}
define WORD_MASK 7UL

为什么要单独把class_getInstanceSize方法拿出来讲一下呢,因为它内部进行字节对齐的代码非常经典(x + WORD_MASK) & ~WORD_MASK

  • 如果x是8的整数倍,则转换成2进制后,其低三位一定是000,加上 WORD_MASK(二进制为111),再&上WORD_MASK取反,就是把低3位置0,刚好保持了原x的值不变。
  • 如果x不是8的整数倍,则其低三3中一定有一个1,加上WORD_MASK(二进制为111)后一定会导致其第四位进位,再&上WORD_MASK取反,则只保留了8的整数倍,也确保了值比x大,所以实现了以8字节对齐的逻辑。

最后

虽然看起来OC对象大小的计算很简单,但在真实场景下我们的对象属性之多,结构之复杂要远超上面的例子,这里只是探究了OC对象在创建过程中的冰山一角。好了,今天就先到这吧~~

未完待续...

相关文章

  • 对象size那点事(二)

    背景 在上篇对象alloc那点事中遗留了一个对象带有基础类型属性后占用内存大小的问题。另外参考之前分析的对象开辟内...

  • 找对象那点事

    到了适婚年龄,必须面对的问题,就是找对象,如果自身条件好就还好,如果自身条件不好,就会像菜市场的蔬菜,被人挑三拣四...

  • isa构造那点事(三)

    背景 在上篇对象alloc那点事中分析对象创建过程,最终是走到_class_createInstanceFromZ...

  • 内存分析

    Shallow Size: 对象本身占用内存大小,不包含其饮用对象。 常规对象(非数组)shallow size ...

  • ios底层原理 文章汇总

    oc对象本质:对象alloc那点事(一)[https://www.jianshu.com/p/a029af32d6...

  • 对象alloc那点事(一)

    在平常开发中我们会经常用到自定义类,并且会调用其alloc+init方法来创建一个实例对象。但是这个过程到底发生了...

  • js关于对象那点事

    js关于对象那点事 每到情人节苦逼的程序猿开始给自己找乐子。 呵 我没有对象 我可以new一个,作为前端更嗨了,万...

  • iOS时间那点事--NSDateFormatter

    文章出处 iOS时间那点事--NSDate iOS时间那点事--NSDateFormatter iOS时间那点事-...

  • 你找的对象是你想找的对象吗

    说说找对象那点事吧 1 提到这个话题是因为闺蜜遇到了渣男,闺...

  • 10-pygame

    一、总体框架 二、文字显示 1、创建字体对象 a.创建系统文字 SysFont ( name, size, b...

网友评论

      本文标题:对象size那点事(二)

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