OC中的内存问题

常见的内存问题有以下几种:

 1.野指针异常:访问没有所有权的内存,如果想要安全的访问,必须确保空间还在

 2.内存泄露:空间使用完之后没有及时释放

 3.过度释放:对同一块存储空间释放多次,立刻crash

 4.内存溢出:所有存储空间被占用

 

管理内存的三种方式:

 1.垃圾回收机制:程序员只需要开辟存储空间,系统会自动回收内存,Java采用该机制

 2.MRC:手动引用计数机制,由开发人员开辟空间,手动添加影响引用计数增加或减少的方法,能够灵活的控制空间何时释放。

 3.ARC:自动引用计数机制,是iOS5.0退出的,基于MRC,不需要程序员手动添加管理内存的代码,编译器会在合适的位置自动添加管理内存的代码。

 MRCARC都是采用引用计数来管理对象内存的

 

// 引用计数机制:

iOS采用引用计数来管理内存,当你想拥有这个对象的时候,需要使该对象的引用计数+1,使用完这个对象的时候,使该对象的引用计数-1,当对象的引用计数为0的时候,表示没有任何对象对该对象持有,那么这时候系统会自动调用dealloc方法来回收该对象的存储空间。

 

// 影响引用计数的方法

 1.使用引用计数+1的方法:allocretaincopy

 2.使用引用计数-1的方法:releaseautorelease

 

下面我们创建一个Person类,还有一个结婚协议(顺道说下协议的问题)

 Person.h

 1 #import <Foundation/Foundation.h>
 2 #import "MarryProtocol.h"   // 引入协议所在的.h文件
 3 
 4 // 让Person类遵守MarryProtocol协议
 5 @interface Person : NSObject <MarryProtocol, NSCopying>
 6 
 7 @property (nonatomic, retain) NSString *name;
 8 @property (nonatomic, retain) NSString *gender;
 9 
10 @end

Person.m

 1 #import "Person.h"
 2 
 3 @implementation Person
 4 
 5 // 重写dealloc方法
 6 // dealloc相当于临终遗言
 7 - (void)dealloc
 8 {
 9     
10     NSLog(@"该对象%@被销毁", self);
11     [super dealloc];   // 让父类回收存储空间,这句话通常写在最后
12 }
13 
14 
15 - (NSString *)description
16 {
17     return [NSString stringWithFormat:@"name = %@, gender = %@", _name, _gender];
18 }
19 
20 
21 // 实现协议中的copyWithZone:方法
22 //- (id)copyWithZone:(NSZone *)zone {
23 //    
24 //    // 伪拷贝:拷贝地址,相当于retain,引用计数+1
25 //    return [self retain];
26 //    
27 //}
28 
29 //- (id)copyWithZone:(NSZone *)zone {
30 //    
31 //    // 浅拷贝:对象开辟新的空间,但两个对象的实例变量指向同一块存储空间(zone是系统申请的内存池)
32 //    Person *person = [[Person allocWithZone:zone] init];
33 //    person.name = self.name;
34 //    person.gender = self.gender;
35 //    
36 //    return person;
37 //}
38 
39 - (id)copyWithZone:(NSZone *)zone {
40     
41     // 深拷贝:对象开辟新的存储空间,并且对象的实例变量指向不同的存储空间(zone是系统申请的内存池)
42     Person *person = [[Person allocWithZone:zone] init];
43     person.name = [self.name mutableCopy];
44     person.gender = [self.gender mutableCopy];
45     return person;
46 }
47 
48 
49 // 实现协议中的方法
50 
51 // 不能家暴
52 - (void)noViolence {
53     NSLog(@"不能家暴");
54 }
55 
56 // 不能出轨
57 - (void)noDerail {
58     NSLog(@"不能出轨");
59 }
60 
61 // 不能抽大烟
62 - (void)noSmoking {
63     NSLog(@"不能抽烟");
64 }
65 
66 // 不能藏私房钱
67 - (void)noSelfMoney {
68     NSLog(@"不能藏私房钱");
69 }
70 
71 
72 // 做家务(可实现也可以不实现)
73 - (void)doHousework {
74     NSLog(@"做家务");
75 }
76 
77 
78 @end

MarryProtocol.h(结婚协议)

 1 #import <Foundation/Foundation.h>
 2 
 3 // 定义一个协议:@protocol...@end
 4 @protocol MarryProtocol <NSObject>
 5 
 6 // 定义方法
 7 
 8 @required // 指定协议中的方法必须遵守
 9 // 不能家暴
10 - (void)noViolence;
11 
12 // 不能出轨
13 - (void)noDerail;
14 
15 // 不能抽大烟
16 - (void)noSmoking;
17 
18 // 不能藏私房钱
19 - (void)noSelfMoney;
20 
21 
22 @optional  // 方法可以实现也可以不实现
23 // 做家务
24 - (void)doHousework;
25 
26 @end

main.m

  1 #import <Foundation/Foundation.h>
  2 #import "Person.h"
  3 
  4 int main(int argc, const char * argv[]) {
  5     @autoreleasepool {
  6         
  7         // alloc的作用:开辟空间,让对象的引用计数由0变成1
  8         Person *person = [[Person alloc] init];
  9 
 10         // 查看对象的引用计数retainCount
 11         // retainCount是MRC才有的机制,所以如果使用的话,需要将ARC转化为MRC
 12         NSUInteger count = person.retainCount;   // 1
 13         NSLog(@"%lu", count);
 14 
 15 
 16         // retain 使对象的引用计数+1
 17         [person retain];   // 2
 18         NSLog(@"%lu", person.retainCount);
 19 
 20 
 21         // release 使对象的引用计数-1
 22         [person release];   // 1
 23         NSLog(@"%lu", person.retainCount);
 24 
 25         [person release];   // 0   当对象的引用计数为0,系统自动调用dealloc方法
 26         person = nil;   // 对象置为nil,防止野指针异常
 27 
 28         // 如果对象已经被回收,当前代码无效
 29         // 开启僵尸模式检查野指针异常
 30         // 如果一个对象被销毁,这个对象就称为僵尸对象
 31         NSLog(@"%lu", person.retainCount);
 32         // 这句话默认情况下不报错,如果要报错,需要开启僵尸模式
 33 
 34 
 35         // autorelease
 36         Person *person1 = [[Person alloc] init];   // 1
 37         Person *person2 = [person1 retain];   // 2
 38         NSLog(@"person1 = %lu, person2 = %lu", person1.retainCount, person2.retainCount);
 39 
 40         Person *person3 = [person1 retain];   // 3
 41         NSLog(@"person1 = %lu, person2 = %lu, person3 = %lu", person1.retainCount, person2.retainCount, person3.retainCount);
 42 
 43         [person3 release];  // 2 立刻-1
 44         NSLog(@"person1 = %lu, person2 = %lu, person3 = %lu", person1.retainCount, person2.retainCount, person3.retainCount);
 45 
 46 
 47         [person2 autorelease];  // 在未来的某个时刻-1
 48         NSLog(@"person1 = %lu, person2 = %lu, person3 = %lu", person1.retainCount, person2.retainCount, person3.retainCount);
 49 
 50 
 51         // 自动释放池
 52         // 定义一个自动释放池
 53         // 第一种形式
 54         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
 55         NSLog(@"%lu", pool.retainCount);
 56 
 57         Person *p1 = [[Person alloc] init];  // 1
 58         NSLog(@"%lu", p1.retainCount);
 59 
 60         [p1 retain];  // 2
 61 
 62         [p1 autorelease];   // 2
 63         NSLog(@"%lu", p1.retainCount);
 64 
 65         [pool release];   // 销毁自动释放池
 66         NSLog(@"%lu", p1.retainCount);   // 1
 67 
 68 
 69         // 对象使用autorelease是在未来的某一个时刻让对象的引用计数-1,这个某一时刻指的是喷到自动释放池之后才会释放
 70 
 71 
 72         // 第二种形式 (在iOS5.0之后推荐使用的)
 73         @autoreleasepool {
 74             Person *p2 = [[Person alloc] init];   // 1
 75             p2.name = @"p2";
 76             [p2 autorelease];   // 0
 77             
 78             Person *p3 = [[Person alloc] init];
 79             p3.name = @"p3";
 80             //[p3 autorelease];
 81         }
 82 
 83 
 84         // 自动释放池的作用:自动释放池会在销毁之前检查内部有没有autorelease操作,如果有autorelease操作,让该对象的引用计数做一次-1操作
 85 
 86 
 87         // 内存管理原则:
 88         // 凡是使用alloc,retain让对象的引用计数+1,相应的就该使用release或者autorelease让对象的引用计数-1,也就是说增加的次数要和减少的次数相等,才能保证对象的引用计数最终为0,对象才会被销毁。
 89 
 90 
 91         // 增加次数和减少次数不一致,会出现内存问题
 92 
 93         // 1.内存泄露:增加的次数大于减少的次数
 94         // 情况1
 95         Person *per1 = [[Person alloc] init];
 96 
 97         // 情况2
 98         Person *per2 = [[Person alloc] init];
 99         [per2 retain];
100         [per2 release];
101 
102         // 情况3
103         Person *per3 = [[Person alloc] init];
104         per3 = nil;
105         [per3 release];
106 
107 
108         // 2.过度释放:增加的次数小于减少的次数
109         Person *q = [[Person alloc] init];
110         [q retain];
111         [q release];
112         [q release];
113         [q release];  // 过度释放
114 
115 
116         // 3.野指针异常:增加的次数等于减少的次数,还将继续访问
117         Person *x = [[Person alloc] init];
118         [x retain];
119         [x release];
120         [x release];
121         //x = nil;   // 没有这一句,就会野指针异常
122         NSLog(@"%lu", x.retainCount);
123 
124         
125         // 并不是所有的对象都能进行copy操作,只有遵循NSCopying协议并实现copyWithZone:方法的对象才能进行copy
126         Person *pe = [[Person alloc] init];
127         pe.name = @"hhh";
128         [pe retain];
129         NSLog(@"%lu", pe.retainCount);
130         Person *pe1 = [pe copy];
131         NSLog(@"%lu, %lu", pe.retainCount, pe1.retainCount);
132         NSLog(@"%p, %p", pe.name, pe1.name);
133         
134         
135         // copy和mutableCopy
136         // copy出来的指针副本是不可变的
137         NSString *str1 = @"詹姆斯";
138         NSString *str2 = [str1 copy];
139         NSLog(@"str1 = %p, str2 = %p", str1, str2);
140         
141         NSMutableString *mStr1 = [str1 copy];
142         NSLog(@"mStr1 = %p", mStr1);
143         
144 //        [mStr1 appendString:@"威武"];
145 //        NSLog(@"%@", mStr1);
146         
147         
148         // mutableCopy拷贝出来的内容是可变的
149         NSString *str3 = [str1 mutableCopy];
150         NSLog(@"str3 = %p, str1 = %p", str3, str1);
151         
152         
153         NSMutableString *mStr2 = [str1 mutableCopy];
154         [mStr2 appendString:@"威武"];
155         NSLog(@"%@", mStr2);
156         
157         
158 //        NSArray *array = @[@"1", @"2", @"3"];
159 //        NSMutableArray *mArray = [array mutableCopy];
160         
161         
162         // 深拷贝和浅拷贝
163         // 如果是深拷贝,那么成员对象的地址和之前的地址不同,如果是浅拷贝,成员变量的地址和之前的相同
164         
165     }
166     return 0;
167 }

 

 

 

转载于:https://www.cnblogs.com/zhizunbao/p/5332696.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值