ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

2021-06-10

2021-06-11 12:29:54  阅读:158  来源: 互联网

标签:10 06 字节 16 内存 cls 对齐 size 2021


iOS 内存对齐

文章目录


最近遇到一个问题 下面person 占用多少的内存?

Person *person = [[Person alloc] init];

一开始的分析如下:

NSLog@(@"%zd".class_getInstanceSize([Person class])); // 打印==8
NSLog(@"%zd",malloc_size((__bridge const void *) person)); // 打印16

一个打印8一个打印16 那个才是person的真实的占用内存大小呢? 我们通过上篇文章分析的到oc对象的本质是一个结构体并且会继承父类NSObiectisa,已知一个isa 的指针式并且占用8个字节?怀着疑问先找到了内存对齐的规则如下:

1. 内存对齐 基本规则

1.数组成员对齐规则: 结构体或联合体的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存储的其实位置要从该成员的大小或子成员大小(只要该成员有子成员,比如说是数组和结构体等)的整数倍开始
例如:

int 为 4 字节,则要从4的整数倍地址开始存储
假如:当前开始位置在8 则int的存储
则为:9 10 11 12
假如:开始位置为9
则为:10(空) 11(空) 12(为4的整数倍则开始存储) 13 14 15 

2.结构体作为成员: 如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储
例如:

struct a {
    double a_a,    [0,7]
    int a_b, [8]
    char a_c, [9]
    struct b, (10,11,12,13,14,15)16+16=32
}a1 32字节

struct b {
    double b_a, //8 字节    [0,7]
    int  b_b, //4 字节      [8,9,10,11]
    char c_c, //1 字节      [12]
}b1 16字节
结构体a 包含结构体b,结构体 b里边最大的是8字节 则存储开始位置应该从8的整数被开始

3.结构体的总大小,必须是其内部最大的整数倍,不足的需要补齐
iOS基本数据类型 字节对照表


在知晓内存对齐规则后结合我们之前分析能的到Person在**c++**代码中的实现应该如下:
结合内存对齐规则 我们可以暂时的出结论Person 所占用的内存是8字节 但是这个16是怎么来的我们需要翻阅一下iOS的源码看下能否得出结论Objc源码 需要编译

struct Person_IMP {
	Class isa;
}

2.分析iOS objc源码内存分配做了什么?

// 我们可以找到如下代码
_class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone,
                              int construct_flags = OBJECT_CONSTRUCT_NONE,
                              bool cxxConstruct = true,
                              size_t *outAllocatedSize = nil)
{
    ASSERT(cls->isRealized());

    // Read class's info bits all at once for performance
    bool hasCxxCtor = cxxConstruct && cls->hasCxxCtor();
    bool hasCxxDtor = cls->hasCxxDtor();
    bool fast = cls->canAllocNonpointer();
    size_t size;
	// 我们可以看出这行代码就是在获取内存大小的 
    size = cls->instanceSize(extraBytes);
    if (outAllocatedSize) *outAllocatedSize = size;

    id obj;
    if (zone) {
        obj = (id)malloc_zone_calloc((malloc_zone_t *)zone, 1, size);
    } else {
    // 这里是分配内存
        obj = (id)calloc(1, size);
    }
    if (slowpath(!obj)) {
        if (construct_flags & OBJECT_CONSTRUCT_CALL_BADALLOC) {
            return _objc_callBadAllocHandler(cls);
        }
        return nil;
    }

    if (!zone && fast) {
    // 关联isa指针
        obj->initInstanceIsa(cls, hasCxxDtor);
    } else {
        // Use raw pointer isa on the assumption that they might be
        // doing something weird with the zone or RR.
        obj->initIsa(cls);
    }

    if (fastpath(!hasCxxCtor)) {
        return obj;
    }

    construct_flags |= OBJECT_CONSTRUCT_FREE_ONFAILURE;
    return object_cxxConstructFromClass(obj, cls, construct_flags);
}
inline size_t instanceSize(size_t extraBytes) const {
// 查阅资料的到这句话的意思是快速计算内存
// 在objc2 中基本上都是快速计算
        if (fastpath(cache.hasFastInstanceSize(extraBytes))) {
            return cache.fastInstanceSize(extraBytes);
        }
/// 
        size_t size = alignedInstanceSize() + extraBytes;
        // CF requires all objects be at least 16 bytes.
        if (size < 16) size = 16;
        return size;
    }
   
 size_t fastInstanceSize(size_t extra) const
    {
        ASSERT(hasFastInstanceSize(extra));

        if (__builtin_constant_p(extra) && extra == 0) {
            return _flags & FAST_CACHE_ALLOC_MASK16;
        } else {
            size_t size = _flags & FAST_CACHE_ALLOC_MASK;
            // remove the FAST_CACHE_ALLOC_DELTA16 that was added
            // by setFastInstanceSize
            // 总这里我们可以看出来iOS 内存分配内存需要16位对齐的 
            return align16(size + extra - FAST_CACHE_ALLOC_DELTA16);
        }
    }

结论: 从以上代码中我们可以看出iOS 对象内存分配是16位对齐的这也就解释了我们开始的问题.

// 获取NSObject 的成员变量所占的字节
NSLog@(@"%zd".class_getInstanceSize([Person class])); // 打印==8
// 获取该对象指针指向的内存大小
NSLog(@"%zd",malloc_size((__bridge const void *) person)); // 打印16

如今问题又来了 为什么需要16位对齐呢?
1.如果是8字节对齐,假设一下,我们创建任意对象都会有isa 指针一个isa 指针8个字节,也就是说多个没有属性的对象,那么它们的内存空间就会完全的挨在一起,容易混乱。从提高寻址效率和内存空间综合考虑。

标签:10,06,字节,16,内存,cls,对齐,size,2021
来源: https://blog.csdn.net/weixin_40115295/article/details/117789151

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有