一、概述

在iOS系统中,程序运行时会将所需的数据图片文件等资源加载到内存。不同类型的数据资
源会加载到不同的内存分区,这些数据资源有的在程序运行时常驻内存,有的会在用完即释放掉。

常驻内存的数据资源所占内存我们暂命名为基础占用内存。当程序执行某个方法时,会在栈空间加载一些数据资源,这时占用内存会升高,函数执行完内存即释放掉。如果执行某个函数过程中加载资源过多,内存占用超出了系统限制,程序会被杀死。如果方法执行过程中对一些生成对象没有做好处理,则会出现内存泄露

二、内存分区

下图是由C/C++/OBJC编译的程序占用内存分布的结构:
Cache Separate

:此处堆栈空间不是数据结构中的堆栈,两者没有关系,不要混淆。

1.栈区 (stack)

栈区由编译器在需要的时候自动分配,不需要的时候自动清除。栈中主要存放局部变量、函数传的参数等。栈是系统的数据结构,应唯一的进程/线程。

栈主要有静态分配动态分配两种分配方式。无论是以哪种方式分配的空间,都无需手动管理释放。相比于堆,栈更加快速高效。

2.堆区(heap)

堆区是由程序员分配和释放的,如果不去释放,在程序结束时候,系统可能会回收内存。但是编程人员应该养成良好习惯,时刻记得处理所分配的内存。在iOS中,使用alloc方式生成的对象都是存放在堆中。

堆区采用链表式管理,在分配内存时操作系统有一个记录空闲内存地址的链表,当接收到程序分配内存的申请时,操作系统就会遍历该链表,遍历到一个记录的内存地址大于申请内存的链表节点,并将该节点从该链表中删除,然后将该节点记录的内存地址分配给程序。不过容易产生内存碎片。

3.全局区/静态区(static)

全局区用来存放静态变量和全局变量,全局区又分为全局初始化区全局未初始化区,用来存放已经初始化和未初始化的全局变量&静态变量。程序结束后由系统释放。

4.文字常量区

文字常量区用来存放常量字符串,程序调用结束后由系统释放。

5.代码区

代码区用来存放函数体的二进制代码。

程序示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
func (int a,char b)		//传入的a,b在栈区
{
int c = 10; //栈区
}

int num = 10; //全局初始化区
char *p1; //全局未初始化区

main()
{
int i; //栈区
char *q; //栈区
char *p2 = “name”; //“name"在常量区,*p2在栈区
char *p3 = "name"; //程序预处理时,会做优化,即在内存中只存取一个”name"字符串,p2,p3均指向它的地址。

UIView *view = [[UIView alloc] init]; //创建UIView对象所需的空间即堆空间。
}

三、内存简单估算

1.图片内存:在iOS系统中,一个APP运行时(一般占用几十兆内存),会加载APP的图标或者一些其他图片。这些图片在APP运行过程中个会一般会常驻内存,如果在程序运行过程中执行某个方法继续加载大量图片,这时内存占用急剧会上升。一般来说:

图片占用内存大小 = 长 4
一张512512图片占用内存大小 = 521 512 * 4 = 1M

在实际的项目开发中,我的加载的图标大小一般为几k或者几十k,可以接受

在iOS中,图片会被自动处理为2的N次方大小,所以512 *1028的图片和1024*1024的图片占用内存大小一样。如果图片由[UIImage imageNamed:@"imgName"]方法加载,则内存占用大小如上所述计算;如果图片由CALayer或者其他类绘制,则大小加倍,因为图片由系统渲染,需要额外消耗内存。

2.程序内存: 在程序启动后,每个函数的执行都要向系统索要资源,这个索要的资源即栈空间。函数执行的局部变量和参数均存放于此。以一个长度为10^5的字符串为例,简单的估算内存:

char 类型占一个字节。
size = 10^5/1024 = 97k //可以接受

一般情况下,栈允许申请空间为2M。当函数执行所需空间大于2M时,系统会报栈溢出的异常。所以在写程序时,应尽量减少大量数据空间的开辟。

另外,很多函数的参数为指针。一个指针的大小与指针的数据类型无关,指针大小是由操作系统决定的(32位系统4个字节,64位系统8个字节),所以无论是一个NString类型的指针,还是一个struct指针,占用内存都一样,而且很小。当一个函数所传参数大小大于8个字节时,最好传指针,这样在函数运行时,会开辟少量栈空间,这也是为什么使用指针比较快的原因之一,因为它只传地址。

3.数据文件内存:与所加载的数据文件大小有关。

内存是系统的宝贵资源,无论是申请还是释放,都需要谨慎处理。在iOS系统中,一个APP一般情况下运行内存应小于70M。尽量避免大量动态开辟内存。例如你的程序正在使用40M内存,然后在执行方法时又动态申请了80M内存,那你的程序会立刻被系统kill。关于内存如何优化,后面会介绍几种方式。
欢迎大家对以上内容勘误。

参考

1.Objective-C中的Block
2.IOS UIImage关于内存占用的思考