ARC 下 我怎么样能主arc 手动释放内存存

iOS- 再谈ARC里内存问题,ARC里数组、对象内存得不到释放?-爱编程
iOS- 再谈ARC里内存问题,ARC里数组、对象内存得不到释放?
1.前言  
& & &本来以为在改成ARC以后,不再需要考虑内存问题了,可是在实践中还是发现有一些内存问题需要注意,今天我不谈block的循环引用的问题,主要说说一些对象、数组不内存得不到释放的情况.
2.数组内存得不到释放的情况  
//组织字典数据
- (NSMutableDictionary *)setupDicData{
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
for (int i = 0; i &= 30; i++) {
[dict setObject:[self setupArrayData] forKey:[NSString stringWithFormat:@"%d%@",i,@"class"]];
//组织数组数据
- (NSMutableArray *)setupArrayData{
NSMutableArray *marry = [NSMutableArray array];
for (int i = 0; i&=30; i++) {
NSString *s = [NSString stringWithFormat:@"%@",@"data-test"];
[marry addObject:s];
- (void)viewDidLoad {
[super viewDidLoad];
while (true) {
//30.0定时执行
[NSThread sleepForTimeInterval:30.0];
NSDictionary *dict = [self setupDicData];
NSLog(@"%@",dict);
//每次数据内存都得不到释放
//按上代码传递数组执行,每次数组、对象内存都得不到释放。如图:
内存会无线的往上增加,直至崩溃。
2.是什么原因导致这种内存得不到释放的?  
主要是你在iOS里使用&&& while (true) {} 无线循环时,
iOS&ARC默认认为你这个方法永远没有执行完,所以不会去主动释放你方法里的对象,这一点和JAVA不一样,
所以很多JAVA开发者转iOS后习惯性的使用while(true){}
导致项目里存在这种内存隐患,导致内存无限增加。
3.如何解决这种数组传递内存得不到释放的情况?  
解决方法一:
3.1.最简单最直接在ARC的环境下使用&&&&&&& @autoreleasepool {}  
//@autoreleasepool {}的作用是在每次循环一次,都会把内存主动释放掉
- (void)viewDidLoad {
[super viewDidLoad];
while (true) {
@autoreleasepool {
//30.0定时执行
[NSThread sleepForTimeInterval:30.0];
NSDictionary *dict = [self setupDicData];
NSLog(@"%@",dict);
//每次数据内存都得不到释放
&内存图,我们发现很稳定,每次都会主动将内存释放
解决方法二:
3.2.使用NSTimer来做数组传递的无限循环,ARC会自动帮你释放内存  
- (void)usingDatadosomething{
//30.0定时执行
[NSThread sleepForTimeInterval:0.10];
NSDictionary *dict = [self setupDicData];
NSLog(@"%@",dict);
//每次数据内存都得不到释放
- (void)viewDidLoad {
[super viewDidLoad];
[NSTimer scheduledTimerWithTimeInterval:30.0 target:self selector:@selector(usingDatadosomething) userInfo:self repeats:YES];
[[NSRunLoop currentRunLoop] run];
&内存图如下
解决方法三:
3.3.使用block封装数组传递,最后做block的释放,ARC会自动帮你释放内存  
block使用较为频繁,不在本文章阐述,下次会专门写一篇block的博客。
谢谢大家,还有什么疑问可以评论中提出,我有时间会耐心回复!
作者:&清澈Saup出处:本文版权归作者和博客园共有,欢迎转载,但必须保留此段声明,且在文章页面明显位置给出原文连接。
版权所有 爱编程 (C) Copyright 2012. . All Rights Reserved.
闽ICP备号-3
微信扫一扫关注爱编程,每天为您推送一篇经典技术文章。2015年4月 移动开发大版内专家分月排行榜第二
2015年5月 移动开发大版内专家分月排行榜第三2015年3月 移动开发大版内专家分月排行榜第三2014年10月 移动开发大版内专家分月排行榜第三
匿名用户不能发表回复!|
每天回帖即可获得10分可用分!小技巧:
你还可以输入10000个字符
(Ctrl+Enter)
请遵守CSDN,不得违反国家法律法规。
转载文章请注明出自“CSDN(www.csdn.net)”。如是商业用途请联系原作者。iOS内存管理之:引用计数、ARC、自动释放池autoreleasepool和便捷方法之间的关系
部分内容摘自《Objective-C基础教程》和互联网
Cocoa采用了引用计数(reference counting)机制,每一个对象有一个关联的“整数retainCount”用于记录对象的使用情况。对象被引用时retaincount+1,外部环境结束对象的使用后retainCount-1.当retaincount为0的时候,该对象被销毁。
当我们使用alloc、new或者copy的我们需要销毁这个对象。release函数,只是将对象的retainCount值减1,并不是删除对象。当retainCount==0的时候,会发给对象一个dealloc消息,另外:千万不要手动调用dealloc,因为我们不知道何时,何地,何人还会使用该对象。应该老老实实依赖引用计数机制完成内存管理。
释放对象所有权的函数除了release还有autorelease,这是一种延迟操作,下面会详细介绍。
当我们看到下面代码,
第一个问题:dateformatter的内存管理,应该很好理解,因为[NSDateFormatter alloc]所以,我们要release它。
-(NSString*) date2String:(NSString*)str
NSString* dateS
currentTime=[NSDate date];
NSDateFormatter
*dateformatter=[[NSDateFormatter alloc] init];
[dateformatter setDateFormat:str];
dateString =[dateformatter stringFromDate:currentTime];
[dateformatter release];
return dateS
那么,这个函数中的NSString* dateString 和NSDate *
currentTime这两个变量,在怎样进行内存管理。还有,局部dateString作为返回值,内存管理又是如何?这是个好问题。
我们发现dateString的赋值方法是 [ dateformatter stringFromDate:current ] ,显然,它并没有使用alloc、new或copy任何一种。《Objective-C基础教程》上说:假设dateString对象被返回时保留引用计数值为1。呵呵,“假设”俩字。这本书还真是基础教程!
刚才《Objective-C基础教程》说过,OC里没有栈上对象,没有临时对象。那么这个dateString算是什么?
那么,现在将他们放到自动释放的范畴,可以这么理解:[ dateformatter stringFromDate:current ] 里面alloc新的对象。这个对象就是autorelease的。
下面将详细介绍自动释放。
自动释放池autoreleasepool
自动释放池是NSAutoreleasePool的实例,其中包含了收到autorelease消息的对象。当一个自动释放池自身被销毁(dealloc)时,它会给池中每一个对象发送一个release消息(如果你给一个对象多次发送autorelease消息,那么当自动释放池销毁时,这个对象也会收到同样数目的release消息)。可以看出,一个自动释放的对象,它至少能够存活到自动释放池销毁的时候。
简单的说一个例子,返回局部堆上变量的指针(用c++的口吻说的),那么这个对象如何释放?Objective-C发明了自动释放机制。
-(obj*) foo
obj* temp = [[obj alloc]init];
return [ obj autorelease];//只是在返回的时候加上关键字autorelease
《Objective-C基础教程》上说:自动释放(autorelease)是一种延迟释放机制,这样保证局部堆上的变量能够被外部正常使用。
但是,系统又是什么时候释放的呢?在每一个事件周期(event cycle)的开始,系统会自动创建一个自动释放池;
在每一个事件周期的结尾,系统会自动销毁这个自动释放池。一般情况下,你可以理解为:当你的代码在持续运行时,自动释放池是不会被销毁的,这段时间内你也可以安全地使用自动释放的对象;当你的代码运行告一段落,开始等待用户输入(或者其它事件)时,自动释放池就会被释放掉,池中的对象都会收到一个release消息,有的可能会因此被销毁。
这是很难确定的时间,如果自动释放池的销毁时间过早,那么程序就很危险,这个恐怕很难满足程序员的要求吧。
自动释放池的缺点:它延缓了对象的释放,在有大量自动释放的对象时,会占用大量内存资源。因此,你需要避免将大量对象自动释放。并且,在以下两种情况下,你需要手动建立并手动销毁掉自动释放池:
1.当你在主线程外开启其它线程时:系统只会在主线程中自动生成并销毁掉自动释放池。
2.当你在短时间内制造了大量自动释放对象时:及时地销毁有助于有效利用iPad上有限地内存资源。
所以,本人不建议使用autorelease的机制,如果遇到上面例子的情况,使用典型的解决方法吧,外部一个对象负责删除obj对象,防止内存泄露。
Convenience method的内存管理
与自动释放相关的,有一大类构造方法(constructor method),由它们构造的对象直接就是自动释放的对象;这一类构造方法叫做便捷方法。比如下面这句的字符串就是一个自动释放的对象,stringWithFormat:就是一个便捷方法。
NSString* string = [NSString stringWithFormat:@”autoreleaseString”];
再举几个便捷方法的例子,方便读者以后的开发。
1.NSArray的arrayWithObjects:和arrayWithArray:。
2.UIImage的imageNamed:。
3.NSNumber的numberWithBool等。
也就是说这些方法返回的对象,我们可以用,但是还是不能确定得知道她什么时候dealloc,那么我们能不能主动删除这些“便捷函数”返回的对象呢?如果,程序中有大量的“便捷函数”,这样无疑占用了大量内存空间。
难道只能避免循环调用这种“便捷函数”?
现在我们已经解释了,autorelease方法会在一段时间以后释放掉一个对象,在这段时间内我们可以安全地使用该对象。那么这段时间究竟是多久呢?
上面已经介绍了自动释放的机制,“便捷函数”产生的对象至少能够存活到自动释放池销毁的时候。
ARC(自动引用计数Auto Reference counting)
上面的文字介绍了“引用计数”这里又来个更高级的自动引用计数。
请参考这篇文章 http://blog.csdn.net/zkdemon/article/details/7446385
/****************************************下面说以下典型的应用****************************?
self.xxx的作用。
NSInteger i =0;
_extraMessage = [[FtExportMessage alloc]init];
//self.extraMessage = [[FtExportMessage alloc]init];
i = [self.extraMessage retainCount];
[self.extraMessage release];
你会发现:运行第一行时,retainCount是1,这个好理解。但是不要使用第二行代码,retaincount是2,及时这个时候你调用release也不会删除对象。
初学者容易犯错,什么地方都用self.XXX.
NSArray和NSDictionary的添加元素,内存管理
这种集合类,只是让“元素”的retainCount加1.同样,当NSDictionary release的时候,会将“元素”
- (void)prepareData
= [[ExportMsgEntity alloc] init];
= [[ExportMsgEntity alloc] init];;
= [[ExportMsgEntity alloc] init];
_msgGroup = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
self.buddyMsg,KMsgBuddy,
self.pgMsg,KMsgPGGroup,
self.dgMsg,KMsgDGGroup,nil];
i = self.buddyMsg.retainC//此时
上面的代码使self.buddyMsg的retainCount从1加1成为2.那么,当NSDictionary析构后呢,请看下面的情况
- (void)deleteDictionary
[self.msgGroup release];
i = self.buddyMsg.retainC//此时 i=1
上面代码使得self.buddyMsg的retainCount从2减1成为1
总结:使用这些“集合”的时候,不要妄想着“集合”release的时候会自动删除里面的元素。最后还是元素自己release资源。详解iOS应用开发中的ARC内存管理方式
作者:M了个J
字体:[ ] 类型:转载 时间:
这篇文章主要介绍了详解iOS应用开发中的ARC内存管理方式,文中示例基于Objective-C语言,需要的朋友可以参考下
提示:本文中所说的"实例变量"即是"成员变量","局部变量"即是"本地变量"
ARC是自iOS 5之后增加的新特性,完全消除了手动管理内存的烦琐,编译器会自动在适当的地方插入适当的retain、release、autorelease语句。你不再需要担心内存管理,因为编译器为你处理了一切
注意:ARC 是编译器特性,而不是 iOS 运行时特性(除了weak指针系统),它也不是类似于其它语言中的垃圾收集器。因此 ARC 和手动内存管理性能是一样的,有时还能更加快速,因为编译器还可以执行某些优化
一、ARC的开启和禁止
要想将非ARC的代码转换为ARC的代码,大概有2种方式:
(1).使用Xcode的自动转换工具
(2).手动设置某些文件支持ARC
1、Xcode的自动转换工具
Xcode带了一个自动转换工具,可以将旧的源代码转成ARC模式
(1).ARC是LLVM 3.0编译器的特性,而现有工程可能使用老的GCC 4.2或LLVM-GCC编译器,因此首先需要设置使用LLVM 3.0编译器:
(现使用的XCode4.5,LLVM 3.0已经升级到LLVM 4.1)
最好也选上Warnings中的Other Warning Flags 为 -Wall,这样编译器就会检查所有可能的警告,有助于我们避免潜在的问题
(2).Build Options下面的Run Static Analyzer选项也最好启用,这样每次Xcode编译项目时,都会运行静态代码分析工具来检查我们的代码
(3).设置"Objective-C Automatic Reference Counting"选项为YES,不过Xcode自动转换工具会自动设置这个选项,这里只是说明一下如何手动设置
(4).打开Xcode的自动转换工具
(5).Xcode会显示一个新窗口,让你选择哪些文件需要转换
点击Check按钮,Xcode可能会弹出对话框提示项目不能转换为ARC,需要你准备好转换(这里暂时省略详细说明)
(6).如果没有什么警告、错误了,就会弹出一下提示窗口:
(7).点击Next,几秒钟后,Xcode会提示所有文件的转换预览,显示源文件的所有改变。左边是修改后的文件,右边是原始文件。在这里你可以一个文件一个文件地查看Xcode的修改,以确保Xcode没有改错你的源文件:
点击Save即可完成转换
(8).自动转换之后,Xcode会移除所有retain、release、autorelease调用,这可能会导致代码出现其它警告、无效语法等,这些都需要自己手工进行修改
注意:Xcode的自动转换工具最好只使用一次,多次使用可能会出现比较诡异的问题。假如你第一次转换没有转换所有的文件,当你稍后试图再次转换剩余的文件时,Xcode实际上不会执行任何转换操作。因此最好一次就完成转换,没有转换的文件可以考虑手工进行修改
2、手动开启某些文件的ARC
在Compiler Flags一列加上-fobjc-arc就表示开启这个.m文件的ARC
3、禁止某些文件的ARC
在Compiler Flags一列加上-fno-objc-arc就表示禁止这个.m文件的ARC
ARC 的规则非常简单:只要还有一个变量指向对象,对象就会保持在内存中。当指针指向新值,或者指针不再存在时,相关联的对象就会自动释放。这条规则对于实例变量、synthesize属性、局部变量都是适用的
三、strong指针
控制器中有个文本输入框框属性
@property (nonatomic, assign) IBOutlet UITextField *nameF&
1.如果用户在文本框中输入mj这个字符串
那么就可以说,nameField的text属性是NSString对象的指针,也就是拥有者,该对象保存了文本输入框的内容
2.如果执行了如下代码
NSString *name = self.nameField.&
一个对象可以有多个拥有者,在上面代码中,name变量同样也是这个NSString对象的拥有者,也就是有两个指针指向同一个对象
3.随后用户改变了输入框的内容,比如
此时nameFeild的text属性就指向了新的NSString对象。但原来的NSString对象仍然还有一个所有者(name变量),因此会继续保留在内存中
4.当name变量获得新值,或者不再存在时(如局部变量方法返回时、实例变量对象释放时),原先的NSString对象就不再拥有任何所有者,retain计数降为0,这时对象会被释放
如,给name变量赋予一个新值
name = @"Jake";&
我们称name和nameField.text指针为"Strong指针",因为它们能够保持对象的生命。默认所有实例变量和局部变量都是Strong指针
四、weak指针
weak型的指针变量仍然可以指向一个对象,但不属于对象的拥有者
1.执行下面的代码
__weak NSString *name = self.nameField.
name变量和nameField.text属性都指向同一个NSString对象,但name不是拥有者
2.如果文本框的内容发生变化,则原先的NSString对象就没有拥有者,会被释放,此时name变量会自动变成nil,称为空指针
weak型的指针变量自动变为nil是非常方便的,这样阻止了weak指针继续指向已释放对象,避免了野指针的产生,不然会导致非常难于寻找的Bug,空指针消除了类似的问题
3.weak指针主要用于“父-子”关系,父亲拥有一个儿子的strong指针,因此父亲是儿子的所有者;但为了阻止所有权循环,儿子需要使用weak指针指向父亲。典型例子是delegate模式,你的ViewController通过strong指针(self.view)拥有一个UITableView, UITableView的dataSource和delegate都是weak指针,指向你的ViewController
五、strong和weak指针的使用注意
1.下面代码是有问题的:
__weak NSString *str = [[NSString alloc] initWithFormat:@"1234"];&
NSLog(@"%@", str); // 打印出来是"(null)"&
str是个weak指针,所以NSString对象没有拥有者,在创建之后就会被立即释放。Xcode还会给出警告("Warning: Assigning retained obj object will be released after assignment")
2.一般的指针变量默认就是strong类型的,因此一般我们对于strong变量不加__strong修饰,以下两行代码是等价的:
NSString *name = self.nameField.&
__strong NSString *name = self.nameField.&
3.属性可以是strong或weak,写法如下
@property (nonatomic, strong) NSString *&
@property (nonatomic, weak)&
4.以下代码在ARC之前是可能会行不通的,因为在手动内存管理中,从NSArray中移除一个对象时,这个对象会发送一条release消息,可能会被立即释放。随后NSLog()打印该对象就会导致应用崩溃
id obj = [array objectAtIndex:0];&
[array removeObjectAtIndex:0];&
NSLog(@"%@", obj);&
在ARC中这段代码是完全合法的,因为obj变量是一个strong指针,它成为了对象的拥有者,从NSArray中移除该对象也不会导致对象被释放
六、ARC小结
1.有了ARC,我们的代码可以清晰很多,你不再需要考虑什么时候retain或release对象。唯一需要考虑的是对象之间的关联,也就是哪个对象拥有哪个对象?
2.ARC也有一些限制:
1& 首先ARC只能工作于Objective-C对象,如果应用使用了Core Foundation或malloc()/free(),此时还是需要你来手动管理内存
2& 此外ARC还有其它一些更为严格的语言规则,以确保ARC能够正常地工作
3.虽然ARC管理了retain和release,但并不表示你完全不需要关心内存管理的问题。因为strong指针会保持对象的生命,某些情况下你仍然需要手动设置这些指针为nil,否则可能导致应用内存不足。无论何时你创建一个新对象时,都需要考虑谁拥有该对象,以及这个对象需要存活多久
4.ARC还能很好地结合C++使用,这对游戏开发是非常有帮助的。对于iOS 4,ARC有一点点限制(不支持weak指针),但也没太大关系
七、ARC使用注意总结
1.不能直接调用dealloc方法,不能调用retain,release,autorelease,retainCount方法,包括@selector(retain)的方式也不行
2.可以用dealloc方法来管理一些资源,但不能用来释放实例变量,也不能在dealloc方法里面去掉[super dealloc]方法,在ARC下父类的dealloc同样由编译器来自动完成
3.Core Foundation类型的对象仍然可以用CFRetain,CFRelease这些方法
4.不能再使用NSAllocateObject和NSDeallocateObject对象
5.不能在C结构体中使用对象指针,如果有类似功能可以创建一个Objective-C类来管理这些对象
6.在id和void*之间没有简便的转换方法,同样在Objective-C和Core Foundation类型之间的转换都需要使用编译器制定的转换函数
7.不能再使用NSAutoreleasePool对象,ARC提供了@autoreleasepool块来代替它,这样更有效率
8.不能使用内存存储区(不能再使用NSZone)
9.不能以new为开头给一个属性命名
10.声明IBOutlet时一般应当使用weak,除了对StoryBoard这样nib中间的顶层对象要用strong
11.weak相当于老版本的assign,strong相当于retain
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具

我要回帖

更多关于 ios arc 强制释放内存 的文章

 

随机推荐