OC 内存管理机制总结

OC 内存管理机制总结

一:OC内存管理机制目前分为两块,其一自动内存管理机制,其二手动内存管理机制:

1.首先我们从自动内存管理机制讲起:

1)什么是自动内存管理机制,自动内存管理机制就是程序中所创造的成员变量交由系统统一处理,不需要外部人员干预,有点像java中gc(垃圾回收机制)。

2)之前是没有自动内存管理机制的,后期苹果想拓展自己的开发市场,吸引其他平台开发者入住ios开发阵营,其中收到内存管理是很发杂的一块,对于转入IOS开发者不利,因此苹果推出了自动内存管理机制。

2.接下来我们将手动内存管理机制:

1)什么又是手动内存管理机制,很好理解,其实参与内存销毁动作交给了程序员去管理,原则是谁创建对象谁销毁对象(内存配对原则)。

二:OC内存管理开发中需要主要那些,其一野指针,其二内存泄漏:

1)那么什么又是野指针,根据网上的理解,指针所指的对象已经被销毁,但后续还在使用该指针,此时指针指向了一个什么都不是的东西,我们称它为野指针,那么如何防止野指针的,一般处理的方式是对象进行release操作后,在赋值对象nil值。

2)那么什么是内存泄漏,根据网上的理解,在操作对象是没有遵循内存配对原则,创建了对象了,却未对对象进行销毁,此时这个未被销毁的对象就是我们所谓的内存中泄漏的对象,这种行为也就是所谓的内存泄漏,内存泄漏不会影响对象的正常运行,但会影响程序的效率。

我们为什么需要内存管理?当使用内存达到40M和45M时候会发出警告,如果不处理,占用内存达到120M时直接强制关闭程序。所以出现闪退除了是程序出现逻辑错误,还有可能是内存使用过大。

(1)创建一个对象的过程:先分配内存空间存储对象;初始化成员变量;返回对象的指针。

(2)对象在创建时,内部会自动创建一个引用计数器retainCount,当retainCount=0时,系统会回收当前对象,retainCount是唯一判断标记。release会-1,retain会+1,retain后返回的是自己self指针。

(3)将ARC关闭调成手动内存管理模式。

(4)内存配对原则:只要有new、alloc或retain,都需要配对一个release或autorelease。

在main.m中,需要把@autorelease pool{}去除,完全靠手动管理:

[objc] view plaincopyprint?

  1. #import <Foundation/Foundation.h>
  2. #import "Person.h"
  3. int main(int argc, const charchar * argv[]) {
  4. //alloc时retainCount=1
  5. Person *p1=[[Person alloc]init];
  6. NSLog(@"%lu",p1.retainCount);
  7. //引用计数=2
  8. [p1 retain];
  9. NSLog(@"%lu",p1.retainCount);
  10. //引用计数=1
  11. [p1 release];
  12. NSLog(@"%lu",p1.retainCount);
  13. //引用计数=0
  14. [p1 release];
  15. //怎么验证此时对象已被销毁呢?每个对象被销毁时会调用dealloc方法,我们重写dealloc,让它输出一些东西,证明被调用了即可
  16. //重写是在这个对象所属类的.m文件中,即本例的Person.m中
  17. return 0;
  18. }
#import <Foundation/Foundation.h>
#import "Person.h"

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

        //alloc时retainCount=1
        Person *p1=[[Person alloc]init];
        NSLog(@"%lu",p1.retainCount);

        //引用计数=2
        [p1 retain];
        NSLog(@"%lu",p1.retainCount);

        //引用计数=1
        [p1 release];
        NSLog(@"%lu",p1.retainCount);

        //引用计数=0
        [p1 release];
        //怎么验证此时对象已被销毁呢?每个对象被销毁时会调用dealloc方法,我们重写dealloc,让它输出一些东西,证明被调用了即可
        //重写是在这个对象所属类的.m文件中,即本例的Person.m中

    return 0;
}

在Person.m中:

[objc] view plaincopyprint?

  1. #import "Person.h"
  2. @implementation Person
  3. -(void)dealloc{
  4. //在对象被销毁之前,先用以下语句释放父类中得相关对象
  5. [super dealloc];
  6. NSLog(@"i am dealloc");
  7. }
  8. @end
#import "Person.h"

@implementation Person

-(void)dealloc{

    //在对象被销毁之前,先用以下语句释放父类中得相关对象
    [super dealloc];
    NSLog(@"i am dealloc");
}

@end

(5)一个对象被回收后,这个对象被称之为僵尸对象,因为Xcode不会时时检查僵尸对象,所以在CMD+R运行时,访问已经被回收的对象有时会报错有时不报错。如果想Xcode时时检查,以下设置。默认是不时时检查,是为了提高编码效率。但建议关闭,因为当类比较多项目大时很耗内存。

(6)手动内存管理研究的两个问题就是:野指针和内存泄露。当对象对回收后,该指针变量没有被设置为nil时,这个指针就是野指针,会导致程序出现闪退。所以我们一般在release后把这个指针变量设置为nil。尽管后续还用到p1,但是p1是nil,向其发送任何消息都没回应也没影响,不会出现闪退。

(7)内存泄露:第一种情况是,不再被使用的对象没有回收一直存在内存中。第二种情况是,不小心先把指针变量设置为nil,然后再[p1 release];已经无效了,此时因为retainCount是唯一标记,尽管没有指针指向这个对象,但对象依然存在在内存中。

[objc] view plaincopyprint?

  1. #import <Foundation/Foundation.h>
  2. #import "Person.h"
  3. int main(int argc, const charchar * argv[]) {
  4. //alloc时retainCount=1
  5. Person *p1=[[Person alloc]init];
  6. NSLog(@"%lu",p1.retainCount);
  7. //引用计数=2
  8. [p1 retain];
  9. NSLog(@"%lu",p1.retainCount);
  10. //引用计数=1
  11. [p1 release];
  12. NSLog(@"%lu",p1.retainCount);
  13. //引用计数=0
  14. [p1 release];
  15. //怎么验证此时对象已被销毁呢?每个对象被销毁时会调用dealloc方法,我们重写dealloc,让它输出一些东西,证明被调用了即可
  16. //重写是在这个对象所属类的.m文件中,即本例的Person.m中
  17. return 0;
  18. }
#import <Foundation/Foundation.h>
#import "Person.h"

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

        //alloc时retainCount=1
        Person *p1=[[Person alloc]init];
        NSLog(@"%lu",p1.retainCount);

        //引用计数=2
        [p1 retain];
        NSLog(@"%lu",p1.retainCount);

        //引用计数=1
        [p1 release];
        NSLog(@"%lu",p1.retainCount);

        //引用计数=0
        [p1 release];
        //怎么验证此时对象已被销毁呢?每个对象被销毁时会调用dealloc方法,我们重写dealloc,让它输出一些东西,证明被调用了即可
        //重写是在这个对象所属类的.m文件中,即本例的Person.m中

    return 0;
}

(8)定义一个p1指针变量后,将其赋值给另一个指针变量p2,那么这个对象retainCount不变,只是多了一个p2指向这个对象而已。任何一个p1和p2都可以release这个对象,release后,这两个指针变量如果不设置为nil就变成野指针。

(9)将指针变量作为参数传递给其他方法时,不会增加其指向对象的引用计数。所以归根结底还是看是否有无retain、new、alloc,以及看是否与release、autorelease配对使用。

(10)Car类是Person类的子类,Person类有个方法是-(void)setCar:(Car *)car{_car=car;}和-(void)drive{[_car run];},run方法是Car类的方法。在主函数中我们的Person对象p1在alloc时候需要配对一个release。如果需要使用[p1 drive];那么需要实例化一个Car对象car1,那么也需要为car1匹配个release。一般是car1的alloc和release被包裹在p1的alloc和release里面。如果我计划在[car1 release];和[p1 release];之间再使用p1的任意方法,比如[p1 drive];发现因为car1已经被release,所以会报错。也就是说,我的p1对象还存在,但是我已经不能任意使用它所有的方法了。怎么解决?

第一步:在setCar方法中修改为_car=[car retain];相当于给这个car1对象的retainCount+1,这样就算我们在主函数中使用配对原则,retainCount仍然还有1,这样p1就可以任意使用。

第二步:就是消除上面仍然存在的car1的retainCount的1,我们的目的是要这个car1的retainCount一直是1,除非我的p1不在了,那car1可以不在。所以我们需要在p1不在的时候把它消除,即在p1的dealloc里面把它消除,消除就是把它[_car release];

(11)接以上问题:如果在主函数里面连续定义两个Car对象变量car1和car2,则最后一个对象变量的内存管理正常,但是前面的几个不正常。因为car1的retainCount还有1,在dealloc里面的_car是car2,所以car2内存正常,car1不正常,内存泄露。解决办法?

问题还是集中在setCar中,在前面增加一句[_car release];如此便好。当第一次调用_car是nil,不影响,转了一圈出去后car1的retainCount为2,当第二次调用时[_car release];里的_car是car1,所以把car1释放了,然后接着把car2的retainCount变成2,随后在主函数以及dealloc中分别释放掉car2。

(12)接以上问题,如果我第二次调用setCar时不时传递car2,而是依然传递的时car1,那么此时在第二次调用时,遇到[_car release];则已经释放了car1,所以下面一句_car=[car retain];就变成野指针操作了。解决办法?

我们给这个[_car release};增加1个判断语句。因为如果是同一个对象没有新对象传递进来的话,_car就一直是这个对象,那么我们会在dealloc中的[_car release];释放掉,而如果后来传递的对象和上一次的不同的话,在dealloc中得[_car release];会变成第二个对象在释放,第一个对象就少了一个释放操作。所以我们的结论是,判断一下,如果传递的新对象是上一次的那个,就不在这个释放,否则就在这里释放。即变成if(_car!=car){[_car release];_car=[car retain];},这句话的核心就是release旧值,retain新值。而且如果传递的和上次一样的对象,则不做任何操作,retainCount仍然是1。

(13)所以,总结成员变量对象的内存管理,就是:a)主要针对setter方法;b)在setter方法中增加一个if(新值!=旧值){release旧值,retain新值};c)并在类的dealloc函数中写一个release。

(14)其实利用@property定义成员变量的时候其实不同的参数就是在指示程序生成不同类型的setter方法。retain是指示程序生成符合内存管理的setter方法,就是上面的if的那一串。而assign则是普通setter方法,所以我们一般对对象类型用retain,而基本数据类型用assign。

但是,关键是上面的retain只是改变了setter方法,并没有自动在dealloc中release。所以,我们在用@property(retain)***的时候,虽然不需要重写setter方法,但是需要重写类的dealloc方法来release释放一次这个成员变量。

(15)顺便,线程管理参数atomic是mac开发的残留物,一般iOS都是nonatomic,而且要书写,因为默认是atomic,所以一般只有两种形式@property(nonatomic,retain)Char *char1;和@property(nonatomic,assign) int age;

(16)顺便,readwrite(生成getter和setter方法)和readonly(只生成getter方法),默认是readwrite。可以利用以下语句更换默认的setter或者getter方法名@property(nonatomic,assign,setter=abc) int age;以后调用setter方法就直接用abc代替。这个一般用在定义BOOL变量时改变setter和getter的名称,一般改成isXXX。

时间: 2024-10-26 03:55:18

OC 内存管理机制总结的相关文章

OC的内存管理机制

总的来说OC有三种内存管理机制,下面将分别对这三种机制做简要的概述. 1.手动引用计数(Mannul Reference Counting-MRC) mannul:用手的,手工的. 引用计数:retaincount 从英文字面上理解就是在这种机制下,内存需要程序员去手动管理,即通过在代码中调用-retain.-release或者-autorelease去增加和减小对象的引用计数,当引用计数为0时,对象会自动调用-dealloc方法释放所占用的内存. 2.垃圾回收机制(Garbage Collec

简述OC中内存管理机制

1.OC的内存管理机制是引用计数, 内存管理原则是谁开辟谁释放, 有retain就要有release. 2. 分为ARC(自动引用计数)和MRC(非自动引用计数), 在MRC下, 我们需要手动管理内存,需要使用到retain/copy/release/autorelease等方法实现内存管理, ARC下一般不需要程序员手动管理内存, 系统会为程序添加自动释放池以实现内存管理, 当然, 咱们说的一般不需要不能理解为完全不需要考虑内存问题, 比如在解决block循环引用问题的时候, 就需要使用__w

简述OC中内存管理机制。

1        简述OC中内存管理机制.与retain配对使用的方法是dealloc还是release,为什么?需要与alloc配对使用的方法是dealloc还是release,为什么?readwrite,readonly,assign,retain,copy,nonatomic .atomic.strong.weak属性的作用? OC使用了一种叫做引用计数的机制来管理对象,如果对一个对象使用了alloc.[Mutable]copy,retain,那么你必须使用相应的realease或者aut

OC内存管理

OC内存管理 一.基本原理 (一)为什么要进行内存管理. 由于移动设备的内存极其有限,所以每个APP所占的内存也是有限制的,当app所占用的内存较多时,系统就会发出内存警告,这时需要回收一些不需要再继续使用的内存空间,比如回收一些不再使用的对象和变量等. 管理范围:任何继承NSObject的对象,对其他的基本数据类型无效. 本质原因是因为对象和其他数据类型在系统中的存储空间不一样,其它局部变量主要存放于栈中,而对象存储于堆中,当代码块结束时这个代码块中涉及的所有局部变量会被回收,指向对象的指针也

OC内存管理(二)

一:autorelease 1> autorelease原理:将我们创建的对象放到一个对象释放池中(是一个栈区)当池子释放时,会将池子中的对象都做一次release操作(自动释放池存放在一个池子中,就近原则,符合先进后出) 2>自动释放池的创建方式 (1)ios 5.0以前的创建方式 NSAutoreleasePool *pool=[[NSAutoreleasePool alloc] init]; ````````````````` [pool  release];//[pool drain]

ARC内存管理机制详解

ARC在OC里面个人感觉又是一个高大上的牛词,在前面Objective-C中的内存管理部分提到了ARC内存管理机制,ARC是Automatic Reference Counting---自动引用计数.有自动引用计数,那么就得有手动引用计数MRC(Mannul Reference Counting),前面已经提到过了MRC.那么在ARC模式下是不是意味着我们就可以一点也不用进行内存管理的呢?并不是这样的,我们还需要代码进行内存的管理.下面会结合着代码把OC中的ARC机制做一个详细的总结(欢迎大家批

oc 内存管理初级

?.内存管理的?式 1.内存常见问题 (1)野指针异常:指针操作已经销毁的对象 指针指向某对象,该对象释放后,该指针即为野指针,对其操作造成野指针异常. 原因:过度释放. (2)内存溢出:超出内存上限 iOS给每个应?程序提供了?定的内存,?于程序的运?.iPhone 3GS内存 30M左右,iPhone 5S 内存80M左右.?旦超出内存上限,程序就会Crash. 2.内存管理的方式 (1)垃圾回收(gc)   |   OC支持 -  OS X开发 支持   |   iOS 不支持 程序员只需

OC内存管理相关整理

OC内存管理 一.基本原理 (一)为什么要进行内存管理.内存管理的目的是什么? 由于移动设备的内存极其有限,所以每个APP所占的内存也是有限制的,当app所占用的内存较多时,系统就会发出内存警告,这时需要回收一些不需要再继续使用的内存空间,比如回收一些不再使用的对象和变量等. 管理范围:任何继承NSObject的对象,对其他的基本数据类型无效 管理目的: 1.不要释放或者覆盖还在使用的内存,这会引起程序崩溃: 2.释放不再使用的内存,防止内存泄露.(ios程序的内存资源很是宝贵.) 本质原因是因

MRC、ARC内存管理机制

MRC下,oc内存管理遵循"谁创建.谁释放.谁引用.谁管理"的机制,当创建或引用一个对象时,需要向她发送alloc,copy,retain消息,当释放该对象时需要发送release消息,当引用计数为零的时候,系统释放该对象. ARC是自动引用计数,管理机制与手动机制一样,只是不再需要调用retain,release,autorelease,它会在适当的位置插入release和autorelease.使用ARC不代表不需要内存管理了,例如使用block时要避免循环引用,代理作为属性时,要