iOS五大内存分区

我们知道任何一个程序在运行的时候实际是运行在内存中的,这个内存也就是我们通常所说的主存,也叫运行内存,也叫RAM(Random Access Memory),是可以直接与CPU进行交换数据的内部存储器。内存读取速度很快,所以作为操作系统运行程序的区域。不同的分区保存不同的值,值可以为指针,可以为对象,可以为二进制代码,可以为数字等,每个分区有自己的功能,它们一起协作为系统提供更好的任务划分。

iOS五大内存分区_第1张图片

堆区(heap)

由程序员管理(分配释放),堆区是由开发者“手动管理”或者程序结束时由系统全部回收,是一种树状的数据结构,一般用于存储由malloc、new等方式创建的对象。在iOS开发中,大多数关于内存管理方面的问题也多出自此:多是一些开发者没有及时回收内存,或者内存溢出以及泄漏等问题。

栈区(stack)

由编译器管理(分配释放),存放函数参数值、局部变量的值(函数中的基本数据类型)栈区的操作方式类似于数据结构中的栈(先进后出)。

全局区(静态区)

由编译器管理(分配释放),程序结束后由系统释放。存放全局变量和静态变量。有两块区域组成全局区(静态区),一块是存放未初始化的全局变量和静态变量,另一块是初始化完成的全局变量和静态变量,这两块区域是相邻的。

文字常量区

由编译器管理(分配释放),主要存储基本数据类型的值,以及常量,同样是进程结束后由系统回收。

程序代码区

存放函数的二进制代码,如果需要执行就加载到该区域中。

特例

这里应该再注意以下几个特例。

1.字符串类型
多个直接声明的相同字符串在内存中只占用一份内存,例如:

     NSLog(@"hello1: %p", @"Hello");
     NSLog(@"hello2: %p", @"Hello");

打印出来的结果是:

     hello1: 0x100001168
     hello2: 0x100001168

这个变量的地址是在常量区中存储,虽然声明的是两个字符串,看似应该开辟两端内存,但通过打印可以看出实际上是同一块内存,这是可以理解的,因为这是同一个固定的字符串,在编译期就确定了的,不会更改,是一个不可变量,因此引用同一份内存并没有什么问题,如果需要在此字符串上进行修改也是另外开辟一段内存。

其实上面的字符串就是__NSCFConstantString,这种字符串存在于常量区,通常的不太短的字符串是__NSCFString,存在于堆区。还有一种是将内容存于地址,叫做标签指针。详情可看:NSString的三种类型管理方式

  1. block类型

block声明的时候是在栈中的,但赋值给变量的时候会复制到堆中。

     //声明一个block
     NSLog(@"block in stack: %p", ^(){});
     //将一个block赋值给一个变量
     id block = ^(){};
     NSLog(@"block in heap: %p", block);

示例代码:
iOS五大内存分区_第2张图片

打印结果:

     a=3, *p=3
     a=3, *p=1

这是关于block作用的一个非常典型的例子,可以很明确地看到block对外部变量的作用。两个方法中,都声明了一个int类型的a,赋值为1,接着声明一个int指针p指向a。在第一个方法中,直接调用了一个block,由于block还没有被赋值,所以这时block还没有复制到堆中,所以对于a来说也没有发生复制,与p指向的为同一内容。所以经过两次加1后,两者都为3;而对于第二个方法,将这个block赋值给一个临时变量,此时根据之前我们所说的内容,发生了复制,__block修饰的a也复制为一份新的内容,但p依然指向之前的内容,此时p的指向和a已经不是同一内容了,所以∗p依然为1,而a经过两次加1后,变为3。

你可能感兴趣的:(ios,cocoa,macos)