美文网首页系统层知识OC 底层
iOS底层原理之内存对齐原理

iOS底层原理之内存对齐原理

作者: 尘舒 | 来源:发表于2019-12-23 02:08 被阅读0次
  • 内存对齐是我们定义数据结构中一个必须要了解的知识点,内存对齐的目的在于能让系统从内存中快速的查找并且获取到我们想要获取的数据,达到空间换取时间的目的。下面简单介绍一下内存对齐的原理

内存对齐的规则

  • 1.数据成员对齐规则,结构体或者联合体的第一个成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员的大小或者该成员的子成员的大小的整数倍开始
  • 2.结构体作为成员:如果一个结构体A中有结构体B作为子成员,B中存放有char,int,double等元素,那么B应该从double也就是8的整数倍开始存储
    1. 结构体的总体大小,即sizeof的结果,必须是其内部最大成员的整数倍,不足的需要补齐

32位下采用4字节对齐,64位下采用8字节对齐

struct A {
    int a; //4字节,0-3
    char b;//1字节,4 补齐567
    double c;// 8字节 8-15
    int *p;  // 8字节 16-23    大小24字节
}AA;

struct B {
    int a; //0,1,2,3 补齐4,5,6,7
    int *p; // 8,9,10,11,12,13,14,15
    char b; // 16补齐17,18,19,20,21,22,23
    double c;// 24,25,26,27,28,29,30,21,32
}BB;

struct C {
    int a; // 0-3,
    char b;// 4,补齐5-7
    double c;// 8-15
    int *p;// 16-23
    struct B bb; //结构体最大成员为8,从24开始,24+32 = 56字节是8的整数倍ok
}CC;
// 输出
NSLog(@"A = %d - B = %d - C = %d",sizeof(AA), sizeof(BB), sizeof(CC));
A = 24 , B = 32, C = 56

对象的内存对齐

  • 对象在alloc过程中,会调用_class_createInstanceFromZone进行内存申请并且创建对象
  • 在calloc之前,首先调用了类的instanceSize方法进行内存空间大小的计算,而在*instanceSize内部采取了8字节对齐的方式,之后为了对象内存安全,在最后返回之前做了最小为16字节的处理,那么可以得出结论,对象的最小内存为16字节
 size_t size = cls->instanceSize(extraBytes);
// 64位下 WORD_MASK为7,也就是8字节对齐
static inline uint32_t word_align(uint32_t x) {
    // (x + 7) >> 3 << 3
    return (x + WORD_MASK) & ~WORD_MASK;
}
static inline size_t word_align(size_t x) {
    return (x + WORD_MASK) & ~WORD_MASK;
}
    uint32_t alignedInstanceSize() {
        return word_align(unalignedInstanceSize());
    }

    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;
    }
  • 之后进入calloc流程,进行具体的内存开辟,在使用calloc申请内存的过程中,首先调用malloc_zone_calloc方法
void *
calloc(size_t num_items, size_t size)
{
    void *retval;
    retval = malloc_zone_calloc(default_zone, num_items, size);
    if (retval == NULL) {
        errno = ENOMEM;
    }
    return retval;
}
  • 在其内部调用zone->calloc初始化并且返回了一个ptr指针
ptr = zone->calloc(zone, num_items, size);
  • 断点到此处,并且打印 zone->calloc ,根据提示找到default_zone_calloc
(lldb) p zone->calloc
(void *(*)(_malloc_zone_t *, size_t, size_t)) $1 = 0x0000000100381a4b (.dylib`default_zone_calloc at malloc.c:249)
(lldb) 
  • default_zone_calloc方法内部又看到熟悉的zone->calloc,继续打印得到提示nano_calloc
(lldb) p zone->calloc
(void *(*)(_malloc_zone_t *, size_t, size_t)) $2 = 0x000000010038302e (.dylib`nano_calloc at nano_malloc.c:878)
(lldb) 
  • 在malloc的源码中搜索nano_calloc,于nano_calloc.h文件中找到该方法,其中的核心代码_nano_malloc_check_clear,进行内存申请,并且返回一个成熟的指针ptr
static void *
nano_calloc(nanozone_t *nanozone, size_t num_items, size_t size)
{
    size_t total_bytes;

    if (calloc_get_size(num_items, size, 0, &total_bytes)) {
        return NULL;
    }

    if (total_bytes <= NANO_MAX_SIZE) {
                // 核心代码,返回一个分配好的地址
        void *p = _nano_malloc_check_clear(nanozone, total_bytes, 1);
        if (p) {
            return p;
        } else {
            /* FALLTHROUGH to helper zone */
        }
    }
    malloc_zone_t *zone = (malloc_zone_t *)(nanozone->helper_zone);
    return zone->calloc(zone, 1, total_bytes);
}
  • 其中_nano_malloc_check_clear方法内部的segregated_size_to_fit则是对象开启内存的大小的算法,表明其实际对齐原则为16字节对齐
#define SHIFT_NANO_QUANTUM      4
#define NANO_REGIME_QUANTA_SIZE (1 << SHIFT_NANO_QUANTUM)

static MALLOC_INLINE size_t
segregated_size_to_fit(nanozone_t *nanozone, size_t size, size_t *pKey)
{
    size_t k, slot_bytes;

    if (0 == size) {
        size = NANO_REGIME_QUANTA_SIZE; // Historical behavior
    }
        //  这里的关键代码进行16字节对齐
        // (size + 1<<4 -1) >> 4
    k = (size + NANO_REGIME_QUANTA_SIZE - 1) >> SHIFT_NANO_QUANTUM; // round up and shift for number of quanta
    slot_bytes = k << SHIFT_NANO_QUANTUM;                           // multiply by power of two quanta size
    *pKey = k - 1;                                                  // Zero-based!

    return slot_bytes;
}

小结

  • 这样基本得出结论,对象内存的申请按照8字节对齐,不满16字节按照16字节计算;但是实际上calloc实际开辟内存的时候,则是进行了16字节对齐,避免对象之间发生溢出和野指针的问题

相关文章

  • iOS--OC底层原理文章汇总

    OC底层原理01—alloc + init + new原理OC底层原理02—内存对齐OC底层原理03— isa探究...

  • OC底层原理汇总

    OC底层原理(一).alloc实际调用流程分析OC底层原理(二).内存分配与内存对齐OC底层原理(三)、isa、对...

  • iOS-底层原理 05:内存对齐原理

    iOS 底层原理 文章汇总 在探讨内存对齐原理之前,首先介绍下iOS中获取内存大小的三种方式 获取内存大小的三种方...

  • ios底层原理 :内存对齐原理

    先介绍一下ios获取内存的三种方式 获取内存大小的三种方式 sizeof class_getInstanceSiz...

  • iOS内存对齐

    这篇文章我们来探索一下iOS内存对齐的原理,在探索完内存对齐原理之后,你就会明白内存对齐的好处。 在讲述内存对齐时...

  • iOS底层原理--内存对齐

    在iOS底层原理--alloc&init&new这篇文章中,我们认识到了字节对齐。那么,我们回顾一下什么是字节对齐...

  • iOS底层-内存对齐原理

    前言 在研究内存字节对齐之前,先通过两个简单的案例了解一下内存大小占用情况: 新建一个工程,创建一个对象:ZLOb...

  • iOS底层原理之内存对齐原理

    内存对齐是我们定义数据结构中一个必须要了解的知识点,内存对齐的目的在于能让系统从内存中快速的查找并且获取到我们想要...

  • iOS底层原理--02 :内存对齐原理

    研究内存对齐原理之前,我们先要熟悉下表:类型对应表.jpg知道对应的内存大小了,接下来我们需要获取内存,验证是否正...

  • iOS底层原理探索—内存原理对齐

    获取内存大小的3种方式 sizeof class_getInstanceSize malloc_size size...

网友评论

    本文标题:iOS底层原理之内存对齐原理

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