iOS-底层(15):iOS内存的五大区

2021-01-19  本文已影响0人  恍然如梦_b700

在iOS中,内存主要分为 栈区、堆区、全局区、常量区、代码区 五大区域。如下图所示

image

下面分别介绍这五大区

栈区(Stack)

定义

存储

栈区是由编译器自动分配并释放的,主要用来存储

优缺点

以上内存大小的说明,在Threading Programming Guide中有相关说明

image

堆区(Heap)

定义

存储

堆区是由程序员动态分配和释放的,如果程序员不释放,程序结束后,可能由操作系统回收,主要用于存放

优缺点

当需要访问堆中内存时,一般需要先通过对象读取到栈区的指针地址,然后通过指针地址访问堆区

全局区(静态区,即.bss & .data)

全局区是编译时分配的内存空间,在iOS中一般以0x1开头,在程序运行过程中,此内存中的数据一直存在,程序结束后由系统释放,主要存放

其中,全局变量是指变量值可以在运行时被动态修改,而静态变量是static修饰的变量,包含静态局部变量和静态全局变量

常量区(即.rodata)

常量区是编译时分配的内存空间,在程序结束后由系统释放,主要存放

字符串常量因为可能在程序中被多次使用,所以`在程序运行之前就会提前分配内存

代码区(即.text)

代码区是编译时分配主要用于存放程序运行时的代码,代码会被编译成二进制存进内存

内存五大区验证

运行下面一段代码,看看变量在内存中是如何分配的

- (void)test{

    NSInteger i = 123;
    NSLog(@"i的内存地址:%p", &i);

    NSString *string = @"CJL";
    NSLog(@"string的内存地址:%p", string);
    NSLog(@"&string的内存地址:%p", &string);

    NSObject *obj = [[NSObject alloc] init];
    NSLog(@"obj的内存地址:%p", obj);
    NSLog(@"&obj的内存地址:%p", &obj);  
}

运行结果如下

image

函数栈

如下图所示,是经典图 - ARM的栈帧布局方式

image

堆栈溢出

一般情况下应用程序是不需要考虑堆和栈的大小的,但是事实上堆和栈都不是无上限的,过多的递归会导致栈溢出过多的alloc变量会导致堆溢出

所以预防堆栈溢出的方法:
(1)避免层次过深递归调用;

(2)不要使用过多的局部变量,控制局部变量的大小;

(3)避免分配占用空间太大的对象,并及时释放;

(4)实在不行,适当的情景下调用系统API修改线程的堆栈大小

栈帧示例

描述下面代码的栈帧变化

栈帧程序示例

int Add(int x,int y) {
    int z = 0;
    z = x + y;
    return z;
}

int main() {
    int a = 10;
    int b = 20;
    int ret = Add(a, b);
}

程序执行时栈区中栈帧的变化如下图所示

image
上一篇下一篇

猜你喜欢

热点阅读