美文网首页
iOS 内存的区域划分与使用

iOS 内存的区域划分与使用

作者: 山杨 | 来源:发表于2021-09-28 14:14 被阅读0次
image.png

代码段

存放编译后的代码

数据段(内存分配:从低地址到高地址)

字符串常量:如:NSString *str = @"xxx";
已初始化数据:已初始化的全局变量、静态变量等
static修饰的变量和全局变量一样地址唯一
未初始化数据:如:int a;

栈(内存分配:从高地址到低地址)

函数调用开销

堆(内存分配:从低地址到高地址)

通过alloc、malloc、calloc等动态分配的内存空间

以下内容都是由一道面试题引发的
下面的代码能正常运行吗?如果可以输出结果是什么?为什么?

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    Class fruit = [YSFruit class];
    void *obj = &fruit;
    [(__bridge id)obj growUp];
}
@end

@interface YSFruit : NSObject
@property (nonatomic, copy) NSString *name;
- (void)growUp;
@end
@implementation YSFruit
- (void)growUp {
    NSLog(@"%@在生长", self.name);
}
@end

结果打印的是:<ViewController>在生长

分析猜测:在growUp方法中self.name的值是ViewController对象,也就是说访问self.name的内存地址和ViewController对象的内存地址相同。又因为(__bridge id)obj中并不存在name属性,所以在使用self.name的时候obj的指针应该是指向了更的高的栈空间地址,而这个地址处刚好存放了ViewController的地址。所以才有了<ViewController>在生长这样的打印结果。

验证一下猜测:

  • 打印obj的下一个指针地址验证
    long long *p = (long long *)obj;
    打印po *(p+1)得到的是ViewController对象
    
  • 在obj和ViewController的地址之间插入一个字符串会不会变成另外一个结果
struct objc_super {
    __unsafe_unretained _Nonnull id receiver;
    __unsafe_unretained _Nonnull Class super_class;
};
// 通过编译成汇编代码得知,[super viewDidLoad]实际是调用objc_msgSendSuper2()
- (void)viewDidLoad {

    struct objc_super superObjc = {self, objc_getClass("ViewController")};
    objc_msgSendSuper2(superObjc, @selector(viewDidLoad));
    // 在obj和ViewController的地址之间插入一个字符串
    NSString *apple = @"苹果";
    
    Class fruit = [YSFruit class];
    // obj指向的是YSFruit类对象和YSFruit的实例对象的isa指针相同
    // 可以看做obj = [YSFruit new]->isa;
    void *obj = &fruit;
    // OC对象本质是以一个isa成员为基础的结构体
    // 由于obj指向YSFruit的类对象,(__bridge id)obj就相当于只有一个isa的YSFruit的一个实例对象
    [(__bridge id)obj growUp];
}

打印结果:苹果在生长

  • 那么就验证了之前的猜测
    原因是栈空间临时变量是按照从高地址到低地址进行存放的,所以通过p/x & obj打印可以获取到obj的栈空间地址,再通过obj的地址向高位查找,使用x/4g obj的栈空间地址打印得到了apple的地址,如果拿掉apple字符串,那么x/4g obj的栈空间地址打印得到的就是ViewController的地址
  • 使用po 栈空间地址打印可以得到栈空间中保存的对象

相关文章

  • iOS 内存的区域划分与使用

    代码段 存放编译后的代码 数据段(内存分配:从低地址到高地址) 字符串常量:如:NSString *str = @...

  • iOS 面试题及答案20道61~80(四)

    iOS 面试题及答案20道61~80(三) 61:谈谈iOS内存 61.1: 内存区域划分 iOS进程内存布局从高...

  • iOS内存管理

    iOS内存管理 内存区域划分 内存区域说明栈区存放局部变量,系统自动分配和释放。 特点:容量小,速度快,有序堆区存...

  • iOS内存中的区域划分

    1.栈:栈区(stack)由系统自动分配和释放,存放方法(函数)的参数值,局部变量的值等。采用“先进后出”或者“后...

  • 面试常见问题03 - 操作系统(施工ing)

    目录 堆内存与栈内存进程和线程同步与异步阻塞与非阻塞... 1. 内存区域 区域划分 堆区与栈区的区别 2. 进程...

  • 内存区域划分

    Java内存分配主要包括以下几个区域: 寄存器:我们在程序中无法控制 栈:存放基本类型的数据和对象的引用,但对象本...

  • 内存区域划分

    iOS内存中分为5个区域: 1、栈区(stack): 一般由编译器操作,会存放一些局部变量,等。 2、堆区(hea...

  • 内存区域划分

    栈区(stack)1)程序运行时由编译器自动分配的一块连续的内容,存放函数的参数值,局部变量的值等2)程序结束时由...

  • 全面理解Java内存模型(JMM)及volatile关键字

    理解Java内存区域与Java内存模型 Java内存区域 Java虚拟机在运行程序时会把其自动管理的内存划分为以上...

  • 理解Java内存模型(JMM)

    理解Java内存区域与Java内存模型 Java内存区域 Java虚拟机在运行程序时会把其自动管理的内存划分为以上...

网友评论

      本文标题:iOS 内存的区域划分与使用

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