------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
1、内存管理
为什么要进行内存管理
移动设备的内存有限,APP的内存会被系统限制,当超出限制会发送消息给APP,此时就需要回收一些不使用的对象和变量,否则程序会崩溃或闪退。
内存管理的范围
管理任何继承NSObject的对象,对其他的数据类型无效。
对象类型是在程序运行过程中动态分配的,存储在堆区。内存管理主要是对堆区中对象的内存管理。
局部变量一般放在栈里面,栈空间存储的东西是自动回收的,代码块完毕后,里面的局部变量会被销毁,也就是一旦没有作用后,就会被系统回收。
2、内存管理的原理
1)对象的所有权和引用计数器
对象所有权:
任何对象都可以拥有一个或者多个所有者,只要一个对象至少还有一个拥有者,他就会继续存在。
在使用 alloc 、new、 copy init 创建对象,新对象的引用计数器默认就是一。
2)对象的引用计数器
每个OC对象都有自己的引用计数器,是一个表示对象被引用的次数,计数器的值变为0时,则对象销毁。
每个OC对象内部,都专门有8个字节的存储空间来引用计数器。
判断对象要不要回收的唯一依据是计数器是不是为0。为0则需要回收。
3)计数器的操作
retain消息 :计数器+1,该方法返回对象本身
release消息:计数器-1,不代表释放了对象
retainCount 消息:获得当前对象的引用计数器值 (%ld %lu)
4)对象的销毁
对象被销毁时,会向系统发送一条 dealloc 消息,一般会重写dealloc方法,在这里释放相关的资源
一旦重写了 dealloc 方法就必须调用[super dealloc],放在代码块的最后调用。
<span style="font-size:12px;">#import "Person.h"
@implementation Person
//注意:dealloc 方法是系统根据引用计数器的值,自动调用的,
//不需要手动调用
- (void)dealloc
{
NSLog(@"Person类已经被回收内存空间");
[super dealloc];
}
@end</span>
5)OC中的内存管理分为3类
手动内存管理(MRC)
自动内存管理(ARC)
垃圾回收(iOS不支持垃圾回收)
所以在开发中我们需要理解MRC,在实际使用尽量用ARC。
3、手动内存管理
什么是内存泄漏
内存泄漏也叫“存储渗漏”,是动态存储分配的内存空间,在使用完毕以后,未被释放,导致其一直占据内存空间。直到程序结束。
导致内存泄漏的可能情况:
<span style="font-size:12px;"> //单个对象的内存泄露问题
//内存泄露情况1:
// 创建完成 使用之后,没有release
// Dog *d = [[Dog alloc] init]; //1
// NSLog(@"%lu",d.retainCount); //使用d对象
//内存泄露情况2:
//没有遵守内存管理的原则
// Dog *d = [[Dog alloc] init]; //1
// [d retain]; //2
// [d release];
// [d release]; //1
//内存泄露的情况3:
//不当的使用了nil
// Dog *d = [[Dog alloc] init]; //1
// d = nil;
//
// [d eat]; //nil eat
// [d release]; // nil release
//内存泄露的情况4:
//在方法中对传入的对象进行了retain
Dog *d = [[Dog alloc] init]; //1
NSLog(@"d.retainCount = %lu",d.retainCount);
//对象依然被泄露了
[d compareColorWithOther:d]; //2
NSLog(@"d.retainCount = %lu",d.retainCount);
[d release];
</span>
set 方法的内存管理
1)基本数据类型
int float double long struct enum
- (void) setSpeed :(int) speed
{
_speed = speed;
}
2)对象作为另外一个类的实例变量
- (void) setDog : (Dog *)dog
{
if (_dog != dog) {
[ _dog release ];
_dog = [ dog retain ];
}
}
@property 参数
4.4之后的增强型格式:
@property (nonatomic , assign) int age;
@property (nonatomic , retain) Car * car;
一般在实例变量是基本数据类型的时候使用 assign 。
在一个类中关联另外一个对象的时候使用 retain 。
@class的使用
作用:简单的引用一个类,告诉编译器这是一个类,而类的方法和属性不会去重新检测
格式:@class 类名;
#import #include @class的区别
#import 和#include 在大部分功能上都是一样的。都是可以引入文件。但是#import 解决了重复引用的问题。
@class 则是声明了一个类,告诉编译器这是一个类,不用去现实,不去管类包含的属性和方法。
#import和 #include 引入一个类会包含这个类的所有信息,这会影响编译器的效率。比如100个类都#import 了同一个类,在编译时这100个类都会对被引用这个进行处理。
自动释放池
1)在iOS程序运行过程中,会创建无数个池子,这些池子都是以栈结构存在的
2)当一个对象调用autorelease,会将这个对象放到位于栈顶的释放池中
自动释放池的创建方式
iOS5.0以后
@autoreleasepool
{//开始代表创建自动释放池
}//结束代表销毁自动释放池
使用autorelease的好处
1)不需要关心对象释放的时间
2)不需要关心什么时候调用release
autorelease的基本用法
1)创建自动释放池
@autoreleasepool
{
}
2)加入自动释放池(引用计数器不会发生变化)
[ 对象 autorelease ];
#import <Foundation/Foundation.h>
#import "Person.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {//创建自动释放池
Person *p = [Person new];
[p run];
NSLog(@"p.retainCount = %lu",p.retainCount);
[p autorelease];//加入到自动释放池
}//结束自动释放池
return 0;
}
------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------