iOS开发--“自动释放池块”降低内存峰值

Objective-C对象的生命期取决于其引用的计数。在Objective-C的引用计数构架中,有一种特征叫做“自动释放池块”(autorelease pool)。释放队形有两个方式:以后总是调用release方式,时期保留计数立即递减:另一种是调用autorelease方法,将其加入”自动释放池“时,系统会将其中多个对象发送release消息。
自动释放池的原理.

  存入到自动释放池中的对象,在自动释放池被销毁的时候.会自动调用存储在该自动释放池中的所有对象的release方法.

   可以解决的问题:

   将创建的对象,存入到自动释放池之中. 就不再需要手动的relase这个对象了.
   因为池子销毁的时候 就会自动的调用池中所有的对象的relase。
    创建自动释放池的语法运用如下:

@autoreleasepool {
//.......
}

    如果在没有创建自动释放池的情况下给对象发送autorelease消息,那么控制台就会输出这样一条消息:

Objective 0xabcd0123 of class __NSCFString autorelease
with no pool in place - just leaking - break on objc

autoreleaseNoPool() to doing
然而,一般情况下无需担心自动释放池的创建问题。Mac OS X 与iOS应用程序分别运用于Cocoa及Cocoa Touch环境中个。系统和会自动创建一些路线,比如说主线或者”大中枢派发“(Grand Central Dispatch,GCD)机制中的线程,这些线程默认都是自动释放,每次执行”事件循环“时,就会进将其清空。因此,不需要自己来创建“自动释放吃”同尘个只有一个地方需要创建自动释放池,那就在main函数里。我们用自动释放池来包裹应用程序的主入口。比方说。iOS程序的面函数经常这样写:
int main(int argh, char *argv[]) {
@autoreleasepool {
return UIApplicationMain(argh,argv,nil,@"EOCAppDelegate");
}
}
从技术角度来看,不是非得有个“自动释放池”才行。应为块的末尾敲好就是应用程序的终结处,二此时操作系统会把程序所占的全部内存全都释放掉,虽然如此,但是如果不写这个块的话,那么有UIApplicationMain函数所自动释放的那些对象,就没有自动释放池可以容纳了,于是西戎会发出警告信息来表明这一情况。所以说,这个吃可以理解成最外围捕捉自动释放对象所用的池。
下面这段代码中的话括号定义了自动化四方吃的范围。自动释放池于左括号处创建,并于对应右括号处清空。位于自动释放池中的对象,将在此范围末尾处收到release的消息。自动释放吃可以嵌套。系统在自动该释放对象的时候,会把它放到最内层的池里。比方说:
@autoreleasepool {
NSString *string = [NSString stringWithFormat:@"1 - %i",1];
@autoreleasepool {
NSNumber *number = [NSNumber numberWithInt:1];
}
}
使用注意

只有在自动释放池中调用了对象的autorelease方法,这个对象才会被存储到这个自动释放池之中.

如果只是将对象的创建代码写在自动释放之中,而没有调用对象的autorelease方法.是不会将这个对象存储到这个自动释放池之中的.
对象的创建可以在自动释放池的外面,在自动释放池之中,调用对象的autorelease方法,就可以将这个对象存储到这个自动释放池之中.

如果对象的autorelease方法的调用放在自动释放池的外面,是无法将其存储的这个自动释放池之中的.

autorelease 的调用只有放在自动释放池之中 才可以讲其存储到自动释放池之中, 对象的创建可以在外面

当自动释放池结束的时候.仅仅是对存储在自动释放池中的对象发送1条release消息 而不是销毁对象.

如果在自动释放池中,调用同1个对象的autorelease方法多次.就会将对象存储多次到自动释放池之中.

在自动释放池结束的时候.会为对象发送多条release消息.
所以,1个自动释放池之中,只autorelease1次,只将这个对象放1次, 否则就会出现野指针错误.
如果在自动释放池中,调用了存储到自动释放中的对象的release方法.

在自动释放池结束的时候,还会再调用对象的release方法.
这个时候就有有可能会造成野指针操作.
将对象存储到自动释放池,并不会使对象的引用计数器+1 所以其好处就是:创建对象将对象存储在自动释放池,就不需要在写个release了.

自动释放池可以嵌套.

调用对象的autorelease方法,会讲对象加入到当前自动释放池之中
只有在当前自动释放池结束的时候才会像对象发送release消息.
autorelease的应用场景.

创建对象,将对象存储到自动释放池之中. 就不需要再去手动的realse。

我们一般情况下,会为我们的类写1个类方法,用来让外界调用类方法来快速的得到1个对象.

规范:使用类方法得到的对象,要求这个对象就已经被autorelease过了.

提供1个类方法来快速的得到1个对象.

规范
这个类方法以类名开头. 如果没有参数就直接是类名 如果有参数就是 类名WithXX:
使用类方法得到的对象,要求这个对象就已经被autorelease过了.

  • (instancetype)person
    {
    return [[[self alloc] init] autorelease];
    }
    以下是我整理的需要注意的事项:
    (1)在自动释放池@autoreleasepool{}中alloc一个对象后,仍然需要用[p1 autorelease];只是这个语句和[p1 release];不同,后者表示把p1的retainCount-1,而前者仅仅表示把p1放到自动释放池中返回一个self,自动释放池结束销毁时,统一对里面的对象引用计数retainCount-1。

(2)@autoreleasepool{}可以随意创建,也可以嵌套使用。

(3)不管这个对象是在自动释放池内还是外创建的,只要在自动释放池内写一个[p1 autorelease];p1就会被放到自动释放池中。注意autorelease是一个方法,且只有在自动释放池中使用才有效。

(4)如果把一个对象重复加到自动释放池如[p1 autorelease];[p1 autorelease];,那么会出错。原因是:加载几次,届时自动释放池就会用[p1 release];释放几次,但是由于这两个加载的对象其实是一个对象同样地址,所以第一次自动释放正确,第二次自动释放时发现已经被释放了,所以p1就变成了野指针。

(5)以下是自动释放池嵌套的使用规则和注意点。
[objc] view plain copy 在CODE上查看代码片派生到我的代码片

import <Foundation/Foundation.h>

import "Person.h"

int main(int argc, const charchar * argv[]) {

Person *p1=[[Person alloc]init];  
@autoreleasepool {  
    @autoreleasepool {  
        [p1 autorelease];  
    }//在执行到此处时,p1被自动释放  
}  
  
//以下代码有错误  
@autoreleasepool {  
    [p1 autorelease];//此时p1被加入进来  
    @autoreleasepool {  
        [p1 autorelease];//被重复加载进来,但仍然同一个  
    }//此处,p1被自动释放了,所以第一次加进来的那个也被释放了,因为是同一个对象  
}//所以此处在调用[p1 release];时就出现报错:野指针  
  
return 0;  

}

(6)@autoreleasepool的应用:如果需要在方法中创建对象,并把这个对象作为返回值,那么可以在这个方法中使用[*** autorelease];把它加入到自动释放池中,否则,直接用[*** release];来匹配alloc的话,在该方法中就已经把这个对象alloc和release了一遍相当于释放了,那么所谓的返回对象返回的时一个野指针(没有指向任何对象)。当然,调用这个方法的代码页需要写在自动释放池作用域内才生效。

(7)接上面。返回对象的那个方法中,创建对象不建议直接用类名,而是用self,否则如果存在子类调用会崩溃。如Car *car1=[[self alloc]init];

(8)其实诸如NSString *str1=[NSString stringWithFormat:@"%@",@"hello"];也是调用了一个方法,并且返回了一个字符串对象。比照(6)和(7)我们得知这个stringWithFormat应该也是顺便返回了一个autorelease。

(9)在ARC机制中,我们用@property声明的成员变量,建议用strong代替之前手动管理内存时的retain,虽然后者仍然可以使用。因为我们在ARC中内存管理就是看是否有强指针指向对象,如有就不回收,如没有就回收。所以强指针是strong,相反是weak。而基本数据类型我们还是习惯用assign。

(10)虽然Xcode提供了非ARC转换成ARC的,很少有把整个非ARC转换成ARC的。如果我们导入第三方库时,需要非ARC和ARC共存,即我们系统默认是ARC,我们需要让系统不要去管这个非ARC的第三方库,如下设置:双击响应的.m文件,输入-fno-objc-arc回车即可。

(11)顺便,当出现两个类循环引用的话(也就是A要包含B,B要包含A,即A对象要作为B的变量,B对象要作为A的变量),只需要把一方的strong改成weak,并且在响应的.h文件中把#import ".h"改成Class ***。如果因为改成Class ***而无法使用那个类的方法的话,只需要在它的.m文件中#import“.h”文件即可,这个因为不是在.h文件中导入所以不冲突。
这就是我整理的关于Autorelease的使用以及“自动释放池块”降低内存峰值的使用方法

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容

  • 内存管理 简述OC中内存管理机制。与retain配对使用的方法是dealloc还是release,为什么?需要与a...
    丶逐渐阅读 1,867评论 1 16
  • 29.理解引用计数 Objective-C语言使用引用计数来管理内存,也就是说,每个对象都有个可以递增或递减的计数...
    Code_Ninja阅读 1,421评论 1 3
  • iOS内存管理 概述 什么是内存管理 应用程序内存管理是在程序运行时分配内存(比如创建一个对象,会增加内存占用)与...
    蚊香酱阅读 5,630评论 8 119
  • 我生君晚生 君成我心老 恨熟不同时 感错才知晓 君来我已去 我来君已往 恨遇不逢时 日日与君好 君来之吾悦 君去之...
    琪人书兰阅读 213评论 0 0
  • 亲爱的小苹果(小屁股): 我们的相处就如我对你的称呼一样,大家都应该想象得出我们是如此多姿的相处。 这一年中你已增...
    夕阳老去西风渐紧阅读 270评论 2 1