------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------
第一讲 C语言中的内存管理
内存管理的基本概念
内存管理,是值软件运行时对计算机内存资源的分配和使用的技术,其最主要的目的是如何高效,快速的分配,并且在适当的时候释放和回收内存资源
内存分配方式有三种:
1)从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在,例如全局变量,static变量。
2)在栈上创建,在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放,栈内存分配运算内置于处理器的指令中,效率很高,但是分配的内存容量有限。
3)从堆上分配,亦称动态内存分配,程序在运行的时候用malloc或new申请任意多少的内存,程序员自己负责在何时用free或delete释放内存,动态内存的生存期由我们决定,使用非常灵活,但问题也最多。
内存分区
BSS段:BSS段通常是指用来存放程序中未初始化的全局变量和静态变量的一块内存区域,BSS属于静态内存分配,BSS段不包含任何数据,只是简单的维护开始和结束的地址,即总大小,以便内存区能在运行时分配并有效的清零,BSS段在应用程序的二进制印象文件中并不存在,即不占用磁盘空间,而只是在运行的时候占用内存空间,所以如果全局变量和静态变量未初始化那么其可执行文件要小很多
数据段:通常是指用来存放程序中已初始化的全局变量和静态变量的一块内存区域,数据段属于静态内存分配,可以分为只读数据段和读写数据段,文字串常量等,但一般都是放在只读数据段中。
代码段:通常是指用来存放程序执行代码的一块内存区域,这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读,某些架构也允许代码段为可写,即允许修改程序,在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等,但一般都是放在只读数据段中。、
堆:堆是用于存放进程运行中被动态分配的内存段,他的大小不固定,可动态扩张或缩减,当进程调用malloc等函数分配内存时,新分配的内存就被动态添加到堆上,当利用free等函数释放内存时,被释放的内存从堆中被剔除,
栈:又称堆栈,是用户存放临时创建的局部变量,也就是说我们函数括号“{}”中定义的变量,除此之外,在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也会被存放会栈中,由于栈的先进先出特点,所以,栈特别方便用来保存/恢复调用现场,从这个意义上讲,我们可以把堆栈看成是一个寄存、交换的临时数据的内存区。
为什么要进行内存动态分配?
以数组为例,一个数组的元素是存储于内存中连续的位置,当数组被声明时其所需要的内存在编译的时候也已经被分配,但是在有些情况下使用这种静态分配方式是不便的,例如使用数组在存储班级中所有学生的成绩,但是不同班级的学生的数量是不同的,在这种情况下,你应该给该数组分配多大的内存呢,一般按照可以容纳可能出现的最多元素来做。
常见的内存分配常数
C语言中提供了三个动态分配函数:malloc,calloc,realloc
1)malloc
使用方法void *malloc(unsigned size)期中size是指分配的内存字节
void *malloc(unsigned size)包含在库函数stdio.h中,作用是内存在堆区分配一个大小为size的连续空间,如果分配内存成功,函数返回新分配内存的首地址,否则返回NULL, 注意:鉴于上述这点,一般在写程序时要判断分配内存是否成功。
如
int *p;
p=(int *)malloc(size(int));
if(p!=NULL){
..............//需要执行的语句
}else{
..............//打印分配内存不成功的信息
}
2)calloc
格式:calloc(块数,长度);
写法与malloc一样
3)relloc
可以给已经存在的空间扩充大小
p=rellpoc(p,40*sizeof(int))
第二讲 OC内存管理
为什么要进行内存管理:
由于移动设备的内存极其有限,所以每个APP所占的内存也是有限制的,当app所占用的内存较多时,系统就会发出内存警告,个app可用的内存是被限制的,如果一个app使用的内存超过20M,则系统会向该app发送Memory Warning消息。收到此消息后,需要回收一些不需要再继续使用的内存空间,比如回收一些不再使用的对象和变量等,否则程序会崩溃。
OC内存管理的范围
管理范围:
管理任何继承NSObject的对象,对其他的基本数据类型无效。
本质原因是因为对象和其他数据类型在系统中的存储空间不一样,其它局部变量主要存放于栈中,而对象存储于堆中,当代码块结束时这个代码块中涉及的所有局部变量会被回收,指向对象的指针也被回收,此时对象已经没有指针指向,但依然存在于内存中,造成内存泄露。
OC内存管理的原理
1)对象的所有权及引用计数
对象所有权概念
任何对象都可能拥有一个或多个所有者。只要一个对象至少还拥有一个所有者,它就会继续存在
Person *p = [[Person alloc] init];
Cocoa所有权策略
任何自己创建的对象都归自己所有,可以使用名字以“alloc”或“new”开头或名字中包含“copy”的方法创建对象,可以使用retain来获得一个对象的所有权
对象的引用计数器
每个OC对象都有自己的引用计数器,是一个整数表示对象被引用的次数,即现在有多少东西在使用这个对象。对象刚被创建时,默认计数器值为1,当计数器的值变为0时,则对象销毁。
在每个OC对象内部,都专门有4个字节的存储空间来存储引用计数器
引用计数器的作用
判断对象要不要回收的唯一依据(存在一种例外:对象值为nil时,引用计数为0,但不回收空间)就是计数器是否为0,若不为0则存在。
对引用计数器的操作
给对象发送消息,进行相应的计数器操作。
retain消息:使计数器+1,该方法返回对象本身
release消息:使计数器-1(并不代表释放对象)
retainCount消息:获得对象当前的引用计数器值
对象的销毁
当一个对象的引用计数器为0时,那么它将被销毁,其占用的内存被系统回收。
当对象被销毁时,系统会自动向对象发送一条dealloc消息,一般会重写dealloc方法,在这里释放相关的资源,dealloc就像是对象的“临终遗言”。
一旦重写了dealloc方法就必须调用[superdealloc],并且放在代码块的最后调用(不能直接调用dealloc方法)。
一旦对象被回收了,那么他所占据的存储空间就不再可用,坚持使用会导致程序崩溃(野指针错误)。