ios开发内存管理及内存泄漏整理总结

一、1、IOS开发中,内存中的对象主要有两类

一类是值类型,比如int、float、struct等基本数据类型。

一类是引用类型,即继承自NSObject类的所有的OC对象。

A、     值类型会被放入栈中,

B、      引用类型会被放到堆中

@ 全局/静态存储区,全局变量和静态变量的存储区域

@栈区,在函数执行过程中,函数内局部变量的存储单元可以在栈上创建,函数执行结束后这些存储单元自动被释放。

@堆区,亦称动态分配区,由程序在运行过程中动态申请分配和管理的区,通常说的内存管理,基本是指对于这一内存区块的管理

@常量区,存储程序运行过程中用到的各种常量,不允许修改

二、Objective-C管理内存的方式

每个对象(特指:类的实例)内部都有一个retainCount的引用计数,

使用alloc, new, copy或者mutableCopy等以及调用addObject等方法时,引用计数器+1,使用release时,引用计数器-1,当引用计数器为0时,对象被释放

1)   iOS内存管理的法则(Swift不适用,Swift自动管理内存)

•  谁创建谁释放

•  谁retain谁释放

2)MRC手动管理内存(人工引用计数)

当引用计数为0的时候,必须回收,引用计数不为0,不能回收,如果引用计数为0,但是没有回收,会造成内存泄露。如果引用计数为0,继续释放,会造成野指针。为了避免出现野指针,我们在释放的时候,会先让指针=nil。

3)ARC自动管理内存(自动引用计数)

在ARC模式下,只要没有强指针(强引用)指向对象,对象就会被释放。在ARC模式下,不允许使用retain、release、retainCount等方法。并且,如果使用dealloc方法时,不允许调用[superdealloc]方法。

ARC模式下的property变量修饰词为strong、weak,相当于MRC模式下的retain、assign。strong:代替retain,缺省关键词,代表强引用。weak:代替assign,声明了一个可以自动设置nil的弱引用,但是比assign多一个功能,指针指向的地址被释放之后,指针本身也会自动被释放。

三、与内存有关的修饰符

@property的参数分为三类,也就是说参数最多可以有三个,中间用逗号分隔,每类参数可以从上表三类参数中人选一个。如果不进行设置或者只设置其中一类参数,程序会使用三类中的各个默认参数,默认参数:(atomic,readwrite,assign)

一般情况下如果在多线程开发中一个属性可能会被两个及两个以上的线程同时访问,此时可以考虑atomic属性,否则建议使用nonatomic,不加锁,效率较高;     

    retain,相当于ARC中的strong

assign,相当于ARC中的weak

属性参数

ARC下基本数据类型默认的属性参数为(atomic,readwrite,assign),对象类型默认的属性参数为(atomic,readwrite,strong)

非ARC下基本数据类型默认的属性参数为(atomic,readwrite,assign),对象的默认属性参数为(atomic,readwrite,retain)


ARC下

assgin : 基本数据类型、枚举、结构体(非OC对象)

strong : 除NSString\block以外的OC对象

copy : NSString,数组,字典,block

weak : 当2个对象相互引用,一端用strong,一端用weak。引用记数不会加1

非ARC下

assign,用于基本数据类型和C数据类型(int, float, double, char)另外还有id

retain,通常用于非字符串对象

copy,通常用于字符串对象、block、NSArray、NSDictionary

@@ strong与copy都是强类型,但这两者有什么区别呢。什么情况下使用copy,什么时候使用strong呢?

copy是深复制,会指向新的对象,即创建新的内存地址。不会跟着赋值的对象的值变化而变化,即不可变。 strong则是指向赋值对象所在的地址,所以当赋值对象值发生变化时,也会跟着改变。

使用copy的概念应该是出于安全的考虑。防止赋值给它的是可变的数据。

所以什么时候使用 strong,赋值对象改变时也要跟着改变。使用copy,赋值对象改变时property不跟着变化。

@@、retain、copy、assign的区别:

1.retain:当对一个对象A调用retain,然后赋值给B时,对象的引用计数加1,A和B指向同一个内存地址。

2.copy:当对一个对象A调用retain,然后赋值给B时,对象的引用计数加1,而且生成了一个新的拷贝,A和B指向不一样的内存地址。

3.assign:当对一个对象A调用retain,然后赋值给B时,对象的引用计数不变,A和B指向同一个地址。


四、那些内存管理中的坑

 1)循环引用

即A持有了B,B持有了A,导致无论是先释放A还是B

解决这种亲密关系导致的循环引用,采用弱引用即可

2)  Block中的坑

  Block在访问对象变量(即类对象)时有两条隐含的retain对象规则,即:

        A、如果访问类属性对象变量,则Block会强引用self,即retain一次类对象本身

3)     B、如果访问了局部对象变量,则Block会强引用局部变量自身一次

3)闭包中循环引用

4) 闭包中变量的访问范围及持有变了隐含规则同Block

4)NSTimer中的对象retain问题

  repeats参数被设置成YES时,target中的对象将永远不会被释放,只有调用invalidate方法之后才会释放target对象,从而释放接收处理target对象。

5)  performSelector中的对象retain问题

只有当执行完成之后才会释放target和argument对象,它的执行前提条件是:1)时间到;2)满足指定的Loop Modes。因此在发起该方法的类销毁之前该方法不一定会被执行,因此就会存在内存泄漏的风险。能否在dealloc或deinit中释放呢?请看客考虑

五、自动释放池

自动内存释放使用@autoreleasepool关键字声明一个代码块,如果一个对象在初始化时调用了autorelase方法,那么当代码块执行完之后,在块中调用过autorelease方法的对象都会自动调用一次release方法。这样一来就起到了自动释放的作用,同时对象的销毁过程也得到了延迟(统一调用release方法)。对象的释放延迟到自动释放池销毁的时候。不过这只是一种半自动的机制。

注意:

1)autorelease不会改变对象的引用记数,如果Person对象引用记数非0,放入自动释放池是无法被销毁的。

2)自动释放池实质是当自动释放池销毁后调用对象的release方法。

3)如果一个操作比较占用内存(对象比较多或者对象占用资源比较多),最好不要放入自动释放池或者考虑放入多个释放池中。

4)ObjC中类库中的静态方法一般都不需要手动释放,内部已经调用了autorelease方法.

1.自动释放池实现了对象的延迟释放,将释放时机延后。当对一个对象调用autorelease方法后,对象被加入自动释放池。当自动释放池释放时,会对自动释放池中的对象调用release方法。

2.主线程会自动创建自动释放池,自己创建的线程需要自己负责创建自动释放池。在一个RunLoop周期开始时,系统会创建一个自动释放池,当RunLoop周期结束时,系统会释放之前创建的自动释放池。如果我们在使用autorelease时没有自己创建自动释放池,对象会在它所在的RunLoop周期结束时被释放掉。一个UI事件,Timer调用,delegate调用,都会是一个新的Runloop。

3.类似于[NSString stringWithFormat:]这样的类方法创建的对象默认是使用了自动释放池的,不需要释放。

4.当在短时间内大量的使用自动释放对象,要手动使用自动释放池来释放对象,否则内存会在短时间内疯涨。

六、循环引用

1.   @class

对于循环依赖关系来说,比方A类引用B类,同时B类也引用A类


这种代码编译会报错。当使用@class在两个类相互声明,就不会出现编译报错

  用法概括

使用@class 类名; 就可以引用一个类,说明一下它是一个类

  和#import的区别(面试题)

l  #import方式会包含被引用类的所有信息,包括被引用类的变量和方法;@class方式只是告诉编译器在A.h文件中 B *b 只是类的声明,具体这个类里有什么信息,这里不需要知道,等实现文件中真正要用到时,才会真正去查看B类中信息

l  如果有上百个头文件都#import了同一个文件,或者这些文件依次被#improt,那么一旦最开始的头文件稍有改动,后面引用到这个文件的所有类都需要重新编译一遍,这样的效率也是可想而知的,而相对来讲,使用@class方式就不会出现这种问题了

l  在.m实现文件中,如果需要引用到被引用类的实体变量或者方法时,还需要使用#import方式引入被引用类

问题:如何解决循环引用的内存管理。

解决方案:一端用assign,一端用retain

/*

 1.@class的作用:仅仅告诉编译器,某个名称是一个类

 2.开发中引用一个类的规范

 1>在.h文件中用@class来声明类

 2>在.m文件中用#import来包含类的所有东西

2.   循环retain

  比如A对象retain了B对象,B对象retain了A对象

  这样会导致A对象和B对象永远无法释放

七、didReceiveMemoryWarning、dealloc方法使用

1.didReceiveMemoryWarning方法:

首先调用[super didReceiveMemoryWarning]方法,然后检查当前视图的父视图是否为空,如果为空,则释放掉一些不需要的数据。关于视图界面的释放不应该在这个方法中,应该放在viewDidUnload方法中。

3.dealloc方法:

对象释放时调用,在这个方法中,要释放掉所有的数据和输出口。比如释放输出口:[xxx release];(不使用self关键字)


八、一些注意的地方

1.向集合(NSArray,NSDictionary等)添加对象时,被添加的对象会被执行retain操作,当从集合中移走对象或者集合对象被释放时,集合中的对象会被执行release操作。

2.要保证有多少个alloc、copy、multablecopy、retain消息,就要有多少个release或者autorelease,保证代码平衡。

3.在程序中直接用@""创建的NSString对象,是常量,引用计数是-1,向它发送retain、release没有效果。

4.在View中使用图片时,大的图片区域尽量使用小的图片数据来填充,减小内存占用。

5.[UIImage imageNamed:@""],次方法使用了系统缓存来缓存图像,会长时间占用内存,最好使用imageWithContentsOfFile方法。

6.数据要延迟加载,只在内存中保留满足需要的最少的数据和视图元素,需要的时候再加载,不需要就马上销毁。

7.假如一个成员变量在property中使用了retain,当使用self关键字对其赋值时,会对创建的对象再retain一次,造成内存泄露。比如:self.xxx = [[XXXalloc] init];

 对一个成员变量赋nil值时,self.xxx = nil,会调用xxx的release方法,并且将指针置空,xxx = nil,只是将指针置空。

9.在控制器中使用NSTimer会使当前控制器引用计数加1,所以在控制器释放之前,必须暂停和使定时器失效,否则控制器将不会被释放。

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

推荐阅读更多精彩内容

  • 1.ios高性能编程 (1).内层 最小的内层平均值和峰值(2).耗电量 高效的算法和数据结构(3).初始化时...
    欧辰_OSR阅读 29,334评论 8 265
  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,090评论 1 32
  • OC语言基础 1.类与对象 类方法 OC的类方法只有2种:静态方法和实例方法两种 在OC中,只要方法声明在@int...
    奇异果好补阅读 4,258评论 0 11
  • 内存管理 简述OC中内存管理机制。与retain配对使用的方法是dealloc还是release,为什么?需要与a...
    丶逐渐阅读 1,950评论 1 16
  • 一棵树。 春节。树回到家乡。少有人知的一个县城。少年时,做火车被问到,你哪的。当树说出XX时,对方一脸茫然,说没听...
    Joy君阅读 369评论 0 2