iOS开发-内存分区与分配

前言

Objective-C从名字来看就可以知道这是一门超C语言,所以了解C语言的内存模型对于理解Objective-C的内存管理、性能优化有很大的帮助。 

 C语言内存模型图如下:

416556-5a074ec54c658b80.png

从图中可以看出内存被分成了5个区,每个区存储的内容都不相同。

1、栈区(stack)

传入函数的参数值、函数体内声明的局部变量等,由编译器自动分配释放,通常在函数执行结束后就释放了。

(注意:不包括static修饰的变量,static意味该变量存放在全局/静态区)

其操作方式类似数据结构中的栈,先进后出。

栈内存分配运算内置于处理器的指令集,效率很高,但是分配的内存容量有限,比如iOS中栈区的大小是2M(看网上说,也有人说1M,我也不知道具体大小,但栈区的内存肯定不会太大)。

我们无法也不需要管理栈区的内存分配。

可以根据下面的代码可以理解:

    int main ()
    {
        int array[] = {1,2,3,4,5};
                              ------------------|
        if ( i > 0 ) {                          |
            ...                                 |
            ...                                 |
        }                                       |
        foo(array);                             |
                                                |
        {                                       |
            int k = 9;        ---               |
            array[1] = k;       |->k的生存域     |->array的生存域
            ...               ---               |
        }                    |->执行到这一步k被释放|
    }                                           |
                                                |
    void foo(int * const number) {              |
        int j = 0;                              |
                              ---               |
        ...                     |               |
        number[2] = j;          |->j的生存域     |
        ...                     |               |
                              -------------------
    }                  |->执行到这一步j、array被释放

当代码中当程序执行到变量生存域(作用域)之外 的时候,变量生存域(作用域)已经结束了,编译器就会自动释放掉变量所占的内存,所以理解好生存域(作用域)就理解了栈区的内存分配。 

2、堆区(heap)

堆区的内存是由代码分配和释放,用于存放进程运行中被动态分配的内存段,堆区的大小并不固定,可动态扩张或缩减。

变量通过new、alloc、malloc、realloc分配的内存块就存放在堆区。

堆区的内存都是动态分配的。

当进程调用alloc等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张)。

当利用realse释放内存时,被释放的内存从堆中被剔除(堆被缩减)。

如果应用程序没有释放掉,操作系统会自动回收,分配方式类似于链表。

因为现在iOS基本都使用ARC来管理对象,所以也不需要手动释放。

一般速度比较慢,而且容易产生内存碎片,不过用起来最方便。

3、全局/静态区

全局/静态区是存放全局变量静态变量的。

已初始化的全局变量和静态变量存放在一块区域。

未初始化的全局变量和静态变量在相邻的另一块区域。

由static修饰的变量会成为静态变量,该变量的内存由全局/静态区在编译阶段完成分配,且仅分配一次。

static可以修饰局部变量也可以修饰全局变量。

全局/静态区的内存在编译阶段完成分配,程序运行时会一直存在内存中,只有当程序结束后才会由操作系统释放。

4、常量区

常量区是一块比较特殊的存储区,常量区里面存放的是常量,常量字符串就存放在常量区。

常量区的内存在编译阶段完成分配,程序运行时会一直存在内存中,只有当程序结束后才会由操作系统释放。

5、代码区

代码区是用来存放可执行文件的操作指令(存放函数的二进制代码),其实就是存放程序的所有代码。代码区需要防止在运行时被非法修改,所以只准许读取操作,而不允许写入(修改)操作——它是不可写的。

下面的代码可以更清晰的理解: 

#import "ViewController.h"

NSInteger age;//age存放在<未初始化的全局静态区>

NSInteger  score = 100;//age存放在<已初始化的全局静态区>

//@"SunSatan"存放在<常量区>,name存放在<已初始化的全局静态区>
NSString *name = @"SunSatan";

static NSString *titleView = @"SunSatan";//titleView存放在<已初始化的全局静态区>

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
    int flag;//flag存放在<栈区>
    NSString *number = @"8090";//number存放在<栈区>,@"8090"存放在<常量区>
    
    //array_1、array_2存放在<堆区>
    NSArray *array_1 = [[NSArray alloc]init];
    NSArray *array_2 = [NSArray array];
    
    NSArray *array_3 = @[];//array_3存放在<栈区>
    
    NSInteger total = [self getTotalNumber:1 number2:1];//total存放在<栈区>
    
}

- (NSInteger)getTotalNumber:(NSInteger)number1 number2:(NSInteger)number2{
    return number1 + number2;//number1、number2存放在<栈区>
}

@end

总结 

在编译阶段代码区、常量区、全局/静态区就已经分配完成并且大小固定,所以指向这些区的指针不会产生崩溃性的错误。

而栈区和堆区内存分配随着程序运行而变化(堆的创建销毁,栈的弹入弹出)。

在iOS中,堆区的内存是应用程序共享的,堆区的内存分配是系统负责的。

 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值