美文网首页
iOS 内存分配原理

iOS 内存分配原理

作者: _Waiting_ | 来源:发表于2021-07-16 20:46 被阅读0次

在64的系统中定义一个NSObject所占的内存是多少呢?
答案是:16个字节
为什么的是16个字节呢?
因为NSObject的底层实现如下:

// NSObject Implementation
struct NSObject_IMPL {
    Class isa; // 8个字节
};

引入

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

打印相关的信息:

NSObject *obj = [[NSObject alloc] init];
 // 16个字节
        
// 获得NSObject实例对象的成员变量所占用的大小 >> 8
NSLog(@"%zd", class_getInstanceSize([NSObject class]));
        
// 获得obj指针所指向内存的大小 >> 16
NSLog(@"%zd", malloc_size((__bridge const void *)obj));

发现实际上创建NSObject所需的内存空间是8个字节,但是系统实际开辟的内存空间是16个字节,问题出在了哪里?
查看源码我们发现一句这样的代码:

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;
    }

当size小于16时,系统会强制转成16个字节,所以系统开辟实际空间为16个字节。

随之而来的一个问题是当我们自己的创建一个类时,实际开辟的内存空间是多少呢?
我们明白,类的本质的结构体,结构体有一个原则叫做内存对齐。

内存对齐主要遵循下面三个原则:

1.结构体变量的起始地址能够被其最宽的成员大小整除。
2.结构体每个成员相对于起始地址的偏移能够被其自身大小整除,如果不能则在前一个成员后面补充字节。
3.结构体总体大小能够被最宽的成员的大小整除,如不能则在后面补充字节。

注:
其实这里有点不严谨,编译器在编译的时候是可以指定对齐大小的,实际使用的有效对齐其实是取指定大小和自身大小的最小值。
参考:如何理解 struct 的内存对齐?

所以真实的大小要看其最大的成员变量的长度,然后进行计算。

举个简单的例子:

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

@interface Student : NSObject{
    @public
    
    int _age;
}


@end

@implementation Student



@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
//        NSLog(@"Hello, World!");
        
        
        
        
        Student *stu = [[Student alloc] init];

        NSLog(@"%zd ",class_getInstanceSize([Student class]));//16
        NSLog(@"%zd ",malloc_size((__bridge  const void *)stu));//16
        
        
        
    }
    return 0;
}
#import <Foundation/Foundation.h>
//#import <objc/runtime.h>
#import <objc/message.h>
#import <malloc/malloc.h>

@interface Student : NSObject{
    @public
    
    int _age;
    int _no;  
}


@end

@implementation Student



@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
//        NSLog(@"Hello, World!");
        
        
        
        
        Student *stu = [[Student alloc] init];

        NSLog(@"%zd ",class_getInstanceSize([Student class]));//16
        NSLog(@"%zd ",malloc_size((__bridge  const void *)stu));//16
        
        
        
    }
    return 0;
}

看两段代码的区别,下面一段代码多了一个 int _no; 但是开辟出来的空间和上面的一样。

模拟一下内存显示: 内存

所以对象开辟的实际内存空间是16个字节

iOS 又有自己分配内存的对齐方式,最大是256个字节,最小是16个字节,(16 32 48 64 80 96 112...为16的倍数),超过256就会采用别的分配内存的方式(暂时不讨论),所以当我们创建的类开辟内存空间的时候,系统会拿大于等于实际内存的整块的大小给你,而不是实际大小。

相关文章

网友评论

      本文标题:iOS 内存分配原理

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