------- iOS培训、Android培训、Java培训、期待与您交流! ----------
【内存管理】
1、内存管理概念
由于移动设备内存及其有限,所以每个app所占的内存也是有限的
需要回收一些不使用的空间
2、OC内存管理的范围
管理任何继承NSOject的对象,对其他的基本数据类型无效
主要管理堆区中的对象的内存管理
3、内存管理的原理
1)对象所有权概念
任何对象都可以能拥有一个或多个所有者,只要一个对象至少还拥有一个所有者,他就会继续存在
cocoasu所有权策略
任何自己创建的对象都归自己所有,可以使用名字以“alloc”或“new”开头或名字中包含“copy”的方法创建对象,可以使用retain来获得一个对象的所有权
对象引用计数器
对象的结构:
3)引用计数器的作用
引用计数器是判断对象要不要回收的依据(对象值为nuil时,引用计数为0,但不回收空间)就是计数器是否为0,若不为0则存在
4)对引用计数器操作
给对象发消息,进行和相应的计数器操作
retain消息,使计数器+1,该方法返回对象本身
release消息,使计数器-1(并不代表释放对象)
retainCount消息,获得对象当前的引用计数器值 %ld %tu
5)对象的销毁
当一个对象的引用计数器为0,那么它将被销毁
系统会自动向对象发送一条dealloc消息,相当于临终遗言;
一旦重写了dealloc方法就必须调用[super dealloc],并且放在代码块的最后调用(不能直接调用dealloc方法)
一旦对象被回收了,那么他所占的储存空间就不再可用,坚持使用会导致程序奔溃(野指针)
注意:
1)如果对象的计数器不为0,那么在整个程序运行过程,它占用的内存就不可能被回收(除非整个程序程序退出)
2)任何对象,刚创建的时候引用计数器为1,当使用alloc、new或者copy创建一个对象时,对象的引用计数器默认就是1
4、OC内存管理分类
三种内存管理方法
1)MRC 手动管理,需要自己控制
2)ARC 自动引用计数(系统默认的模式)
3)垃圾回收(ios不支持垃圾回收)
实际使用时尽量用ARC
【手动内存管理】
1 1、关闭ARC的方法 2 1)设置项目类信息 3 //dealloc方法,是对象的临终遗言 4 //对象被销毁时会自动调用该方法 5 //注意:dealloc方法是系统自动调用的,不需要手动调用 6 -(void)dealloc{ 7 // 先释放子类自己的对象空间 8 NSLog(@"已经销毁"); 9 // 再释放父类的 10 [super dealloc]; 11 } 12 13 #import <Foundation/Foundation.h> 14 #import "Person.h" 15 int main(int argc, const char * argv[]) { 16 @autoreleasepool { 17 // 用person类实例化一个实例对象 18 Person * p = [Person new]; 19 // 证明有一个所有者 20 NSLog(@"%ld",[p retainCount]);//1 21 // 使用引用机器数+1 22 // 调用两次 23 [p retain]; 24 NSLog(@"%ld",[p retainCount]); 25 // 回收对象 26 [p release]; 27 NSLog(@"%ld",[p retainCount]); 28 [p release];//此处执行后,p的空间被回收0 29 30 // NSLog(@"%ld",[p retainCount]); 31 // 证明p的空间被释放,可以在person类中,重写dealloc方法 32 } 33 return 0; 34 }
1、内存管理原则
1)原则
只要还有人在使用对象。那么这个对象就不会被回收
只要你想使用这个对象,那么就应该让这个对象的引用计数器+1、
当你不想使用这个对象,应该让对象的引用计数器-1;
2)谁创建,谁release
(1)如果你通过alloc、new、copy来创建了一个对象,那么你就必须调用release或者autor
(2)不是你创建你就不用去负责
3)谁retain谁release
只要你调用了retain,无论这个对象如何生成,你都要release
4)有始有终,有加就要有减
2、内存管理研究内容
1)野指针:
(1)定义的指针变量没有初始化
(2)指向的空间已经被释放
2)内存泄露
{
Person * p = [Person new];
}
p栈区
[Person new] 堆区
如果栈区的已经被释放了,而堆区的空间还没有释放,堆区的空间就被泄露了
【单、多个对象的内存管理】
1、单个对象的野指针问题
如果一个对象已经被释放了,就是一个僵尸对象
//这句化默认不报错,已经释放了是一个僵尸对象,这个p已经是一个野指针了
僵尸对象:所占用空间已经被回收的对象
注意:
1)空指针,没有指向任何东西的指针,给空指针发信息不会报错
nil类的初始化
【NSNull null】是一个对象,用在不能使用nil的场合
2)[p retain];不能使僵尸对象复生
3)野指针操作
已经释放不能再用指针访问方法
2、避免使用僵尸对象
1)方法:
释放对象后,给对象赋值为nil
p = nil;
2)泄露情况:
(1)创建完成,使用之后,没有release
(2)没有遵守内存管理的原则,计数器没有归0;
(3)不当的使用了nil,没有释放之前就给对象赋值为nil;
(4)在方法中对传入的对象进行了retain
3、多个对象野指针问题(栈区指针还在,堆区已经释放了)
一个人对象,一个车对象,车对象销毁后,人就无法调用车方法,野指针
4、多个对象的泄露问题(栈区指针回收,堆区空间未释放)
多个对象,问题,可以嵌套销毁,在dealloc重写里面加上调用的对象销毁语句;
car = nil;
self .car = nil
5、set方法的内存管理
1 )-(void)setCar{
if(_car !=csr){
[_car release];
[_car relain];
}
}
2)如果是基本对象,直接赋值
3)如果在一个类中,有其他类对象,关联关系,set方法书写,先release旧值,再retain新值,还要判断是否是同一个对象
【*@property参数】
1、*@property参数
格式:@property(参数1,参数2)数据类型 方法名
原子性:一件事情完成之前,另一件事情无法进行;
retain中又if判断
@property (nonatomic,retain) NSString *picture;
@interface Dog : NSObject
@property (nonatomic,readwrite,assign) int age;
@end
1)多线程管理
用默认的atomic
2)set方法名替换
@property (setter=isVip:,getter=isVip) int age;
【@class的使用】
1、@class使用
//#import作用:
//把要引用的头文件的内容,拷贝到写#import处
//如果Goods.h头文件内容发生变化了,此时所有引用了头文件的都要重新编译
#import "Goods.h"
@class Goods;
@class可以简单的引用一个类
使用格式:@class 类名;
@class xxx
含义:告诉编译器,xxxx是一个类,至于类有哪些属性和方法,此处不去检测、
好处:如果xxxx文件内容发生了改变,而不需要重新编译
简单便捷,效率高
缺点:只是告诉编译器有一个类,但是并没有去检查里面的方法,不能直接调用
解决方法:在使用的时候在.m文件中用#import引用头文件
在运行的时候才在.m文件中进行检查,提高了效率;
注意:
1).h @class xx;
2).m #import xx.h;
2、@class可以解决循环引入问题
A<->B互相引用,用@class可以解决,#import会报错
3、@class和#import区别
1)作用上区别
2)效率上区别
【NSString类的内存管理】
1、NSString类的内存管理
1 NSString *str1 = @"abc";//@"abc"字符串的常量 2 3 4 5 NSString *str2 = [NSString stringWithFormat:@"aaa"];//不是在栈区,在堆区 6 7 //常量区 8 9 NSString *str3 = [NSString stringWithString:@"abc"]; 10 11 //不是在栈区,在堆区 12 13 NSString *str4 = [[NSString alloc]initWithFormat:@"aaa"]; 14 15 16 17 NSString *str5 = [[NSString alloc]initWithString:@"abc"];//常量区 18 19 int a = 10;//栈区 20 21 NSLog(@"%p",&a); 22 23 NSLog(@"str1 = %@,%p,%lu",str1,str1,str1.retainCount); 24 25 NSLog(@"str2 = %@,%p,%lu",str2,str2,str2.retainCount); 26 27 NSLog(@"str3 = %@,%p,%lu",str3,str3,str3.retainCount); 28 29 NSLog(@"str4 = %@,%p,%lu",str4,str4,str4.retainCount); 30 31 NSLog(@"str5 = %@,%p,%lu",str5,str5,str5.retainCount); 32 33 } 34 35
【autorelease使用】
1、自动释放池
自动释放池
1)在ios程序运行过程中,会创建很多自己释放池,是栈结构,先进后出
2)当一个对象调用autorelease时,会将这个对象放到位于栈顶得释放池中
自动释放方式
@autoreleasepool
{开始自动释放
}结束自动释放
它可以暂时的保存某个对象,然后再内存池自己的排干的时候对其中每一对象发送release信息,不一定释放,只是-1;
2、使用@@autorelease好处
1)不需要关心对象释放的时间
2)不需要关系什么时候调用release