OC中的内存问题
常见的内存问题有以下几种:
1.野指针异常:访问没有所有权的内存,如果想要安全的访问,必须确保空间还在
2.内存泄露:空间使用完之后没有及时释放
3.过度释放:对同一块存储空间释放多次,立刻crash
4.内存溢出:所有存储空间被占用
管理内存的三种方式:
1.垃圾回收机制:程序员只需要开辟存储空间,系统会自动回收内存,Java采用该机制
2.MRC:手动引用计数机制,由开发人员开辟空间,手动添加影响引用计数增加或减少的方法,能够灵活的控制空间何时释放。
3.ARC:自动引用计数机制,是iOS5.0退出的,基于MRC,不需要程序员手动添加管理内存的代码,编译器会在合适的位置自动添加管理内存的代码。
MRC和ARC都是采用引用计数来管理对象内存的
// 引用计数机制:
iOS采用引用计数来管理内存,当你想拥有这个对象的时候,需要使该对象的引用计数+1,使用完这个对象的时候,使该对象的引用计数-1,当对象的引用计数为0的时候,表示没有任何对象对该对象持有,那么这时候系统会自动调用dealloc方法来回收该对象的存储空间。
// 影响引用计数的方法
1.使用引用计数+1的方法:alloc,retain,copy
2.使用引用计数-1的方法:release,autorelease
下面我们创建一个Person类,还有一个结婚协议(顺道说下协议的问题)
Person.h
#import <Foundation/Foundation.h>
#import "MarryProtocol.h" // 引入协议所在的.h文件 // 让Person类遵守MarryProtocol协议
@interface Person : NSObject <MarryProtocol, NSCopying> @property (nonatomic, retain) NSString *name;
@property (nonatomic, retain) NSString *gender; @end
Person.m
#import "Person.h" @implementation Person // 重写dealloc方法
// dealloc相当于临终遗言
- (void)dealloc
{ NSLog(@"该对象%@被销毁", self);
[super dealloc]; // 让父类回收存储空间,这句话通常写在最后
} - (NSString *)description
{
return [NSString stringWithFormat:@"name = %@, gender = %@", _name, _gender];
} // 实现协议中的copyWithZone:方法
//- (id)copyWithZone:(NSZone *)zone {
//
// // 伪拷贝:拷贝地址,相当于retain,引用计数+1
// return [self retain];
//
//} //- (id)copyWithZone:(NSZone *)zone {
//
// // 浅拷贝:对象开辟新的空间,但两个对象的实例变量指向同一块存储空间(zone是系统申请的内存池)
// Person *person = [[Person allocWithZone:zone] init];
// person.name = self.name;
// person.gender = self.gender;
//
// return person;
//} - (id)copyWithZone:(NSZone *)zone { // 深拷贝:对象开辟新的存储空间,并且对象的实例变量指向不同的存储空间(zone是系统申请的内存池)
Person *person = [[Person allocWithZone:zone] init];
person.name = [self.name mutableCopy];
person.gender = [self.gender mutableCopy];
return person;
} // 实现协议中的方法 // 不能家暴
- (void)noViolence {
NSLog(@"不能家暴");
} // 不能出轨
- (void)noDerail {
NSLog(@"不能出轨");
} // 不能抽大烟
- (void)noSmoking {
NSLog(@"不能抽烟");
} // 不能藏私房钱
- (void)noSelfMoney {
NSLog(@"不能藏私房钱");
} // 做家务(可实现也可以不实现)
- (void)doHousework {
NSLog(@"做家务");
} @end
MarryProtocol.h(结婚协议)
#import <Foundation/Foundation.h> // 定义一个协议:@protocol...@end
@protocol MarryProtocol <NSObject> // 定义方法 @required // 指定协议中的方法必须遵守
// 不能家暴
- (void)noViolence; // 不能出轨
- (void)noDerail; // 不能抽大烟
- (void)noSmoking; // 不能藏私房钱
- (void)noSelfMoney; @optional // 方法可以实现也可以不实现
// 做家务
- (void)doHousework; @end
main.m
#import <Foundation/Foundation.h>
#import "Person.h" int main(int argc, const char * argv[]) {
@autoreleasepool { // alloc的作用:开辟空间,让对象的引用计数由0变成1
Person *person = [[Person alloc] init]; // 查看对象的引用计数retainCount
// retainCount是MRC才有的机制,所以如果使用的话,需要将ARC转化为MRC
NSUInteger count = person.retainCount; //
NSLog(@"%lu", count); // retain 使对象的引用计数+1
[person retain]; //
NSLog(@"%lu", person.retainCount); // release 使对象的引用计数-1
[person release]; //
NSLog(@"%lu", person.retainCount); [person release]; // 0 当对象的引用计数为0,系统自动调用dealloc方法
person = nil; // 对象置为nil,防止野指针异常 // 如果对象已经被回收,当前代码无效
// 开启僵尸模式检查野指针异常
// 如果一个对象被销毁,这个对象就称为僵尸对象
NSLog(@"%lu", person.retainCount);
// 这句话默认情况下不报错,如果要报错,需要开启僵尸模式 // autorelease
Person *person1 = [[Person alloc] init]; //
Person *person2 = [person1 retain]; //
NSLog(@"person1 = %lu, person2 = %lu", person1.retainCount, person2.retainCount); Person *person3 = [person1 retain]; //
NSLog(@"person1 = %lu, person2 = %lu, person3 = %lu", person1.retainCount, person2.retainCount, person3.retainCount); [person3 release]; // 2 立刻-1
NSLog(@"person1 = %lu, person2 = %lu, person3 = %lu", person1.retainCount, person2.retainCount, person3.retainCount); [person2 autorelease]; // 在未来的某个时刻-1
NSLog(@"person1 = %lu, person2 = %lu, person3 = %lu", person1.retainCount, person2.retainCount, person3.retainCount); // 自动释放池
// 定义一个自动释放池
// 第一种形式
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSLog(@"%lu", pool.retainCount); Person *p1 = [[Person alloc] init]; //
NSLog(@"%lu", p1.retainCount); [p1 retain]; // [p1 autorelease]; //
NSLog(@"%lu", p1.retainCount); [pool release]; // 销毁自动释放池
NSLog(@"%lu", p1.retainCount); // 1 // 对象使用autorelease是在未来的某一个时刻让对象的引用计数-1,这个某一时刻指的是喷到自动释放池之后才会释放 // 第二种形式 (在iOS5.0之后推荐使用的)
@autoreleasepool {
Person *p2 = [[Person alloc] init]; //
p2.name = @"p2";
[p2 autorelease]; // Person *p3 = [[Person alloc] init];
p3.name = @"p3";
//[p3 autorelease];
} // 自动释放池的作用:自动释放池会在销毁之前检查内部有没有autorelease操作,如果有autorelease操作,让该对象的引用计数做一次-1操作 // 内存管理原则:
// 凡是使用alloc,retain让对象的引用计数+1,相应的就该使用release或者autorelease让对象的引用计数-1,也就是说增加的次数要和减少的次数相等,才能保证对象的引用计数最终为0,对象才会被销毁。 // 增加次数和减少次数不一致,会出现内存问题 // 1.内存泄露:增加的次数大于减少的次数
// 情况1
Person *per1 = [[Person alloc] init]; // 情况2
Person *per2 = [[Person alloc] init];
[per2 retain];
[per2 release]; // 情况3
Person *per3 = [[Person alloc] init];
per3 = nil;
[per3 release]; // 2.过度释放:增加的次数小于减少的次数
Person *q = [[Person alloc] init];
[q retain];
[q release];
[q release];
[q release]; // 过度释放 // 3.野指针异常:增加的次数等于减少的次数,还将继续访问
Person *x = [[Person alloc] init];
[x retain];
[x release];
[x release];
//x = nil; // 没有这一句,就会野指针异常
NSLog(@"%lu", x.retainCount); // 并不是所有的对象都能进行copy操作,只有遵循NSCopying协议并实现copyWithZone:方法的对象才能进行copy
Person *pe = [[Person alloc] init];
pe.name = @"hhh";
[pe retain];
NSLog(@"%lu", pe.retainCount);
Person *pe1 = [pe copy];
NSLog(@"%lu, %lu", pe.retainCount, pe1.retainCount);
NSLog(@"%p, %p", pe.name, pe1.name); // copy和mutableCopy
// copy出来的指针副本是不可变的
NSString *str1 = @"詹姆斯";
NSString *str2 = [str1 copy];
NSLog(@"str1 = %p, str2 = %p", str1, str2); NSMutableString *mStr1 = [str1 copy];
NSLog(@"mStr1 = %p", mStr1); // [mStr1 appendString:@"威武"];
// NSLog(@"%@", mStr1); // mutableCopy拷贝出来的内容是可变的
NSString *str3 = [str1 mutableCopy];
NSLog(@"str3 = %p, str1 = %p", str3, str1); NSMutableString *mStr2 = [str1 mutableCopy];
[mStr2 appendString:@"威武"];
NSLog(@"%@", mStr2); // NSArray *array = @[@"1", @"2", @"3"];
// NSMutableArray *mArray = [array mutableCopy]; // 深拷贝和浅拷贝
// 如果是深拷贝,那么成员对象的地址和之前的地址不同,如果是浅拷贝,成员变量的地址和之前的相同 }
return ;
}
OC中的内存问题的更多相关文章
- OC中的内存管理
一. 基本原理 1. 什么是内存管理 移动设备的内存极其有限,每个app所能占用的内存是有限制的 当app所占用的内存较多时,系统会发出内存警告,这时得回收一些不需要再使用的内存空间.比如回收一些不需 ...
- OC中最难的一部分内容:内存管理
OC中最难的一部分内容:内存管理为什么说他难呢?因为内存如果需要我们程序员去管理的话,那个难度肯定是很大的,如果是Java,垃圾回收器会把这份工作给做了,我们不需要关心,但是就是因为如此,Androi ...
- Unity游戏开发中的内存管理_资料
内存是手游的硬伤——Unity游戏Mono内存管理及泄漏http://wetest.qq.com/lab/view/135.html 深入浅出再谈Unity内存泄漏http://wetest.qq.c ...
- C++中的内存管理
在C++中也是少不了对内存的管理,在C++中只要有new的地方,在写代码的时候都要想着delete. new分配的时堆内存,在函数结束的时候不会自动释放,如果不delete我分配的堆内存,则会造成内存 ...
- Objective-C中的内存管理
在编程语言中是少不了对内存的管理的,内存对于计算机来说是宝贵的资源,所以对使用不到的资源进行回收是很有必要的.OC中使用引用计数和垃圾回收来管理内存,在OC中为每个对象分配一个引用计数器,当对象刚刚被 ...
- java中的继承与oc中的继承的区别
为什么要使用继承? 继承的好处: (1)抽取出了重复的代码,使代码更加灵活 (2)建立了类和类之间的联系 继承的缺点: 耦合性太强 OC中的继承 1.OC中不允许子类和父类拥有相同名称的成员变量名:( ...
- iOS-旧项目中手动内存管理(MRC)转ARC
在ARC之前,iOS内存管理无论对资深级还是菜鸟级开发者来说都是一件很头疼的事.我参 加过几个使用手动内存管理的项目,印象最深刻的是一个地图类应用,由于应用本身就非常耗内存,当时为了解决内存泄露问题, ...
- Oc中的数组
========================== 数组 ========================== 一.认识数组 oc中可以把NSObject对象的子类放到数组这个集合中,但是int.f ...
- OC中面向对象2
一. 定义OC的类和创建OC的对象 接下来就在OC中模拟现实生活中的情况,创建一辆车出来.首先要有一个车子类,然后再利用车子类创建车子对象 要描述OC中的类稍微麻烦一点,分2大步骤:类的声明.类的实现 ...
随机推荐
- 【原创】14. MYSQL++之SSQLS(原理解析)
从之前所介绍的SSQLS的介绍中我们可以感受到,SSQLS的精髓应该在sql_create_#这个宏,他所创建出来的这个结构体将会是突破的关键,所以我将会从以下顺序入手. 1. sql_create_ ...
- (转)Netfilter分析
看到一篇讲Netfilter框架的,如果有一点基础了的话对于捋清整个框架很好帮助,转下来细细阅读. 转自http://aichundi.blog.163.com/blog/static/7013846 ...
- 快乐的JS正则表达式(开篇)
我不喜欢一开始就去讨论某某有多强大,因为我觉得那样没意思,首先我们的知道它是干什么,对我们有啥用,再去讨论它的强大之处也不迟.那和往常一样我们先来看几个例子. var arr = [1,4,2,5,2 ...
- PowerMock 简介--转载
原文地址:https://www.ibm.com/developerworks/cn/java/j-lo-powermock/ EasyMock 以及 Mockito 都因为可以极大地简化单元测试的书 ...
- Android 学习笔记之网络通信基础+WebView....
PS:加快学习进度...下周一完成Android网络通信...然后正式进入实战... 学习内容: 1.Android中Http基础... 2.Android中的Socket基础... 3.Androi ...
- jquery判断radioButton是否被选中
so easy HTML: <input type='radio' style='width:20px' id='other' name='projectType' value='其他' /&g ...
- ActiveMQ学习(二)——MQ的工作原理
如图所示 首先来看本地通讯的情况,应用程序A和应用程序B运行于同一系统A,它们之间可以借助消息队列技术进行彼此的通讯:应用程序A向队列1发送一条信息,而当应用程序B需要时就可以得到该信息. 其次是远程 ...
- MySQL 备份与还原详解
相关阅读: MySQL备份和恢复具体实施 http://www.linuxidc.com/Linux/2012-12/76257.htm MySQL备份与恢复的三种方法总结 http://www.li ...
- struts2重点——ValueStack和OGNL
一.值栈(ValueStack) 1.实现类:OGNLValueStack 2.对象栈:CompoundRoot(针对的是类级别的) (1)继承自 ArrayList —— 先进后出 (2)提供了栈的 ...
- Sprint 3计划
一.计划目标: 1.完成基本的首页面的信息查询功能 2.学生家教用户注册和登录,将信息存储到数据库 3.完成家教的资格评定设定和个人教学内容备份信息 二.燃尽图 三.项目具体工作细则 待明天工作会议分 ...