内存管理(一):栈区、堆区,成员变量和局部变量,alloc,retain,自动释放池,成员变量及属性的内存管理
2015-07-15 18:12
411 查看
内存问题体现在两个方面:内存泄露,野指针异常。
了解内存管理,能帮我们提升程序性能,大大减少程序bug时间。
1. 内存管理原则
使用者必须保证在使用的周期内是安全的
2. 栈区、堆区
栈区,所有的变量都在栈区,栈区的变量指向堆区,栈区由系统管理内存(出生命周期被自动释放掉)
堆区,对象在堆区,堆区的每一块内存不能起名,堆区的内存需手动释放
a 在栈区,p 在栈区(指向Person所产生的对象),Person 在堆区
栈区 p --> 堆区 对象
p 释放掉,对象没有释放 --> 内存泄露
对象释放掉,p没有释放掉 --> 野指针异常
3. 成员变量、局部变量
成员变量和局部变量的最大区别在于生命周期
局部变量最大的特点是它只是在方法内部定义的变量(变量名的生命周期)
引用计数的平衡:局部变量保证在它所在的{}中平衡,成员变量保证在类中平衡
4. alloc
alloc 代表:创建一个引用计数为1的对象
release:引用计数-1
引用计数添加在堆上
保证在使用的时候安全,保证在不使用的时候消失
谁让引用计数+1,谁就负责引用计数-1
通过类方法创建的对象是自动释放的,它已经添加到自动释放池
5. retain
retain:引用计数+1
传入的参数是可变字典(NSMutableDictionary)时,用dictionaryWithDictionary:方法
6. 自动释放池
自动释放池的创建有两种:
(1) 创建一个自动释放池(只能在MRC中使用)
注意:
1) 只有autorelease所修饰的对象才能添加到自动释放池中
2) 对象所添加的自动释放池是离它最近(离[c1 autorelease];最近)的自动释放池中
3) 代码在自动释放池里写
4) 如果想要在自动释放池中创建对象并使用(将对象放到自动释放池中),必须用autorelease进行声明,添加到离它最近的自动释放池中,c1添加到pool1中
5) 自动释放池释放时,会将自动释放池中的对象一一释放
(2) 简易的(既可以在MRC又可以在ARC中使用)
7. 成员变量及属性的内存管理
保证引用计数为1,并在dealloc中释放
1) 如果在类中声明了成员变量,那么成员变量的创建必须在init中并且必须保证引用计数为1,并在dealloc中释放
2) 如果在类中声明了属性,那么对属性的赋值时必须通过 点语法(调用setter geetter) 来进行赋值(为了保证引用计数为1,且避免内存泄露),并在dealloc中释放
例子:
Car.h文件
1) 如果在类中声明了成员变量,那么成员变量的创建必须在init中并且必须保证引用计数为1,并在dealloc中释放
2) 如果在类中声明了属性,那么对属性的赋值时必须通过 点语法 来进行赋值(为了保证引用计数为1,且避免内存泄露),并在dealloc中释放
Car.m文件
main 中
重写init方法,在init方法中初始化 成员变量_array 和 属性mArr,在这里就不用初始化了
通过便利构造器对属性赋值
打印结果:
name
堆区,对象在堆区,堆区的每一块内存不能起名,堆区的内存需手动释放
了解内存管理,能帮我们提升程序性能,大大减少程序bug时间。
1. 内存管理原则
使用者必须保证在使用的周期内是安全的
2. 栈区、堆区
栈区,所有的变量都在栈区,栈区的变量指向堆区,栈区由系统管理内存(出生命周期被自动释放掉)
堆区,对象在堆区,堆区的每一块内存不能起名,堆区的内存需手动释放
int a = 10; Person *p = [[Person alloc] init];
a 在栈区,p 在栈区(指向Person所产生的对象),Person 在堆区
栈区 p --> 堆区 对象
p 释放掉,对象没有释放 --> 内存泄露
对象释放掉,p没有释放掉 --> 野指针异常
3. 成员变量、局部变量
成员变量和局部变量的最大区别在于生命周期
局部变量最大的特点是它只是在方法内部定义的变量(变量名的生命周期)
引用计数的平衡:局部变量保证在它所在的{}中平衡,成员变量保证在类中平衡
// 只是在方法内部定义的变量(变量名的生命周期) - (void)change { NSString *a = @"hello"; // {...} 是单独的可以存在的 { // b 只在它所在的{}中有效,{}是一个生命周期 NSString *b; NSLog(@"a = %@", a); } // b 在它所在的{}外无效 // NSLog(@"b = %@", b); }
4. alloc
alloc 代表:创建一个引用计数为1的对象
release:引用计数-1
引用计数添加在堆上
Car *c = [[Car alloc] init]; c.name = @"奥迪"; [c release];
保证在使用的时候安全,保证在不使用的时候消失
谁让引用计数+1,谁就负责引用计数-1
通过类方法创建的对象是自动释放的,它已经添加到自动释放池
5. retain
Car *c2 = [[Car alloc] init]; [c2 retain]; [c2 release]; [c2 release];
retain:引用计数+1
- (void)getUrl:(NSString *)url dic:(NSDictionary *)dic { NSDictionary *myDic = [dic retain]; // ...... [myDic autorelease]; } - (void)getUrl:(NSString *)url myDic:(NSMutableDictionary *)dic { NSMutableDictionary *mDic = [NSMutableDictionary dictionaryWithDictionary:dic]; // ...... }传入的参数是不可变字典(NSDictionary)时,需将dic先retain一下再给myDic赋值,再使用
传入的参数是可变字典(NSMutableDictionary)时,用dictionaryWithDictionary:方法
6. 自动释放池
自动释放池的创建有两种:
(1) 创建一个自动释放池(只能在MRC中使用)
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSAutoreleasePool *pool1 = [[NSAutoreleasePool alloc] init]; // 代码在自动释放池里写 Car *c1 = [[Car alloc] init]; [c1 autorelease]; // 自动释放池释放时,会将自动释放池中的对象一一释放 [pool1 release]; [pool release];
注意:
1) 只有autorelease所修饰的对象才能添加到自动释放池中
2) 对象所添加的自动释放池是离它最近(离[c1 autorelease];最近)的自动释放池中
3) 代码在自动释放池里写
4) 如果想要在自动释放池中创建对象并使用(将对象放到自动释放池中),必须用autorelease进行声明,添加到离它最近的自动释放池中,c1添加到pool1中
5) 自动释放池释放时,会将自动释放池中的对象一一释放
(2) 简易的(既可以在MRC又可以在ARC中使用)
<pre name="code" class="objc">@autoreleasepool { Car *c = [[Car alloc] init]; [c release]; }
7. 成员变量及属性的内存管理
保证引用计数为1,并在dealloc中释放
1) 如果在类中声明了成员变量,那么成员变量的创建必须在init中并且必须保证引用计数为1,并在dealloc中释放
2) 如果在类中声明了属性,那么对属性的赋值时必须通过 点语法(调用setter geetter) 来进行赋值(为了保证引用计数为1,且避免内存泄露),并在dealloc中释放
例子:
Car.h文件
#import <Foundation/Foundation.h> #import "Person.h" @interface Car : NSObject { @public // 成员变量 NSMutableArray *_array; } // 成员变量的setter方法 - (void)setArray:(NSMutableArray *)array; // 成员变量的getter方法 - (NSMutableArray *)array; // 属性 @property (nonatomic, retain) NSString *name; @property (nonatomic, retain) NSMutableArray *mArr; @property (nonatomic, retain) Person *per; // 便利构造器 + (Car *)car; + (Car *)carWithName:(NSString *)name mArr:(NSMutableArray *)mArr per:(Person *)per; @end保证引用计数为1,并在dealloc中释放
1) 如果在类中声明了成员变量,那么成员变量的创建必须在init中并且必须保证引用计数为1,并在dealloc中释放
2) 如果在类中声明了属性,那么对属性的赋值时必须通过 点语法 来进行赋值(为了保证引用计数为1,且避免内存泄露),并在dealloc中释放
Car.m文件
#import "Car.h" @implementation Car - (void)dealloc { [_array release]; [_mArr release]; [_per release]; [super dealloc]; } - (instancetype)init { self = [super init]; if (self) { // 成员变量初始化 // 为了使_array使用安全,有两种方法 // 1. 用retain // 类方法 // _array已经添加到自动释放池中,假设引用计数为0,为了使引用计数为1,需要retain一下 // _array = [[NSMutableArray array] retain]; // 2. 用alloc _array = [[NSMutableArray alloc] init];// 为了使引用计数为1 // 属性初始化 // NSString不需要初始化(特殊,引用计数为-1) self.mArr = [NSMutableArray array];// 为了使引用计数为1,且避免内存泄露 // 自定义的对象需要初始化 self.per = [Person person]; } return self; } // 成员变量的setter方法(必须这样写) // 赋值时要保证赋给的值是安全的 - (void)setArray:(NSMutableArray *)array { // _array和array是指针,指向地址 if (_array != array) {// 判断_array和array所指向的地址是否一样,不一样时调用这个方法,地址一样的时候存放的值相同,不调用这个方法 // 在OC的开发中空对象调用任何方法是没有意义的,空对象指向的地址是nil // 第一次调用时为空,为空时再释放无影响 // 第二次及以后调用时先将上一次增加的一次释放,再指向下一个地址 [_array release];// 防止内存泄露 // array(指针) -> 地址 => _array -> 地址(与array同一地址) _array = [array retain];// 防止成为野指针 } } // 成员变量的getter方法(不用非这样写,可以把retain和autorelease去掉) - (NSMutableArray *)array { [_array retain]; return [_array autorelease]; } // 便利构造器所返回的对象添加到自动释放池中 + (Car *)car { Car *c = [[Car alloc] init]; // 保证在使用的时候安全,保证在不使用的时候消失 // 谁让引用计数+1,谁负责引用计数-1 // 返回一个可以使用的值,用autorelease释放 return [c autorelease]; } + (Car *)carWithName:(NSString *)name mArr:(NSMutableArray *)mArr per:(Person *)per { Car *c = [[Car alloc] init]; // 在便利构造器中对成员变量及属性赋值,不能对成员变量赋值 // c ->_array = array; c.name = name; c.mArr = mArr; c.per = per; return [c autorelease]; } @end
main 中
Car *c3 = [[Car alloc] init]; // c3 -> _array = [NSMutableArray array]; // c3.mArr = [NSMutableArray array]; [c3 release];
重写init方法,在init方法中初始化 成员变量_array 和 属性mArr,在这里就不用初始化了
NSMutableArray *mArr = [NSMutableArray array]; Person *p1 = [[Person alloc] init]; Car *c4 = [Car carWithName:@"name" mArr:mArr per:p1]; NSLog(@"%@", c4.name); [p1 release];
通过便利构造器对属性赋值
打印结果:
name
堆区,对象在堆区,堆区的每一块内存不能起名,堆区的内存需手动释放
相关文章推荐
- liunx GHOST clonezilla(再生龙)UltraISO刻录问题
- 解决Robotium测试中Installation error INSTALL_FAILED_VERSION_DOWNGRADE错误
- Communications Link failure
- 关于android.intent.action.MAIN与android.intent.category
- 2013 Multi-University Training Contest 4
- 通过手机页面获取当前城市
- Rails4 中 因为secret key 引起在production环境下无法运行
- toj3852. Haitang1
- push-pull和open drain
- [Win32SDK基本]ListView Controls(2)Report (details) View 详解(续)
- container_of的使用
- DDD(Domain Driver Designer) 领域驱动设计简介
- Scala之Trait的使用
- poj 1273 Drainage Ditches(最大流)
- CONTAINING_RECORD IN EFI
- RapidMiner studio之MainFrame源码分析
- Windows Mobile Emulator:Failed to open the VPC Network Driver.
- HDU 2686 Matrix 3376 Matrix Again(费用流)
- Microsoft.AlphaImageLoader滤镜讲--透明处理<转>
- HTTP Error 503. The service is unavailable