Objective-C 【单个对象内存管理】

———————————————————————————————————————————

单个对象内存管理

(1)野指针

①定义了一个指针变量,但是并没有赋初值,它随机指向一个东西

②某指针变量指向的内存空间被释放掉了(指向僵尸对象的指针)

(2)僵尸对象

已经被销毁的对象(无法被使用的对象)

(3)空指针

没有指向存储空间的指针(里面存的是nil,也就是0)

给空指针发消息是没有任何反应的,不会提示出错

代码:

#import <Foundation/Foundation.h>

@interface Person : NSObject

-(void)run;

@end

@implementation Person

-(void)run

{

NSLog(@"run!");

}

- (void)dealloc

{

NSLog(@"retainCount的结果为0,对象内存被释放!");

[super dealloc];

}

@end

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

@autoreleasepool {

Person *p=[[Person alloc]init];

NSLog(@"[p retainCount]=%tu",[p retainCount]);  //值为1

[p run];

NSLog(@"[p retainCount]=%tu",[p retainCount]);  //值还是为1,当前只有一个使用对象p的,也就是他自己,引用对象p的次数并没有增加

[p retain];

NSLog(@"[p retainCount]=%tu",[p retainCount]);  //值为2

[p release];

NSLog(@"[p retainCount]=%tu",[p retainCount]);  //值为1

[p release];//这里的计数器值为0,内存被释放

//       [p run];    //内存释放之后run方法还是可以调用的

//        那么问题来了,上面run方法是在对象p的堆区内存被释放之后调用的,为什么还会调用成功呢?现在我们就来解决也是上节课遗留的问题

//        首先当p对象被release之后(内存被释放),p就是一个野指针(僵尸对象)了

//        我们知道,虽然p在堆区的内存空间被释放了,但是内存空间是不会变的还在那儿,栈区中也存在p。只是p已经失去了那一部分内存的管理权。如果此时你非要去使用这块空间的话,且这块内存空间没有分配给其他的程序,其实还是能获取到内容的。但是如果这块释放了的空间又被分配给其他的变量或者程序,这时候使用就不对了。

//        而且还有一点,就是上面释放之后又调用run方法,不一定能百分百的调用,可能10次会出现一次调用错误的情况,这也就是野指针的危险。所以说,就不能用僵尸对象调用!!调用是完全无意义的!

//        [p retain];

//        这样是完全错误的,我们上面已经将p所指向的对象内存释放,那么该对象就成为了僵尸对象,我们就不能够这样让其复活(这样硬来得到的值也是错误的结果)

//        为了避免我们使用僵尸对象,我们可以做这样一个处理

p=nil;

//        这样处理过后,编译器在执行下列语句的时候就不会报错了。

[p run];//不会执行,因为p为nil

[p retain];//也不会让计数+1,还是因为p为nil(空值)

NSLog(@"[p retainCount]=%tu”,p.retainCount);

//点语法(  这里相当于将p.retainCount——>[p  retainCount]  )

}

return 0;

}

★那么我们应该怎么防止野指针的调用呢?

操作步骤就是上面的两幅图了,将第二幅图标记的地方打勾,那么再使用野指针运行就会报错了!

Enable Zombie Objects 就是开启僵尸模式~

★★★关于nil和Nil以及NULL的区别

nil:首先这是一个空指针,而且这是一个OC的对象,是一个对象值,如果我们把一个对象设为空的话,我们就要设为nil  (  #define nil ((id) 0)   )

Nil:这是一个类对象值,如果把一个类对象设为空,那么我们就要设为Nil

NULL:是一个通用指针(泛型指针) (    #define NULL ((void *) 0 )   )

NSNull: [ NSNull  null ]  是一个对象,用在不能使用nil的场合

还有最后一点我们 需要注意的,那就是当我们释放了一个对象的内存空间,让该对象成为了僵尸对象,那么是不能够  用 [p  retain];  让它复活的。在上面的程序中有体现。

(4)内存泄漏

代码:

#import <Foundation/Foundation.h>

@interface Car : NSObject

-(void)run:(Car *)cccc;

@end

@implementation Car

- (void)dealloc

{

NSLog(@"释放内存!");

[super dealloc];

}

-(void)run:(Car *)cccc

{

NSLog(@"车在跑");

[cccc retain];//在方法内部使用retain让cccc的计数+1

}

@end

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

@autoreleasepool {

//        (4)内存泄漏问题

//        ① retain 的次数 和 release 的次数 不匹配

//        Car *car=[Car new];

//        NSLog(@"car->retainCount=%tu",car.retainCount);//1

//

//        [car retain];

//        [car retain];

//        [car retain];

//

//        NSLog(@"car->retainCount=%tu",car.retainCount);//4

//

//        [car release];

//

//        NSLog(@"car->retainCount=%tu",car.retainCount);//3

////        显然  retain 的次数 和 release 的次数 是不匹配的。retainCount 不为0,那么空间自然没有被回收释放

////        如果不想让内存泄漏,那么必须 retain + new = release  (增加引用计数=减少引用计数)

////        ②对象在使用过程中被赋值了nil

//        Car *car1=[Car new];

//

//        [car1 retain];

//        [car1 retain];

//        [car1 retain];

//        NSLog(@"car1->retainCount=%tu",car1.retainCount);//4

//

//        car1=nil;

//        [car1 release];//其实这四条release语句是没有作用的 ,是 [nil release]; ,我们知道向nil发送什么指令都不会报错,但是此时原对象car1的空间是没有被释放的,所以说最后car1的内存还是被泄漏了。

//        [car1 release];

//        [car1 release];

//        [car1 release];

//

//        NSLog(@"car1->retainCount=%tu",car1.retainCount);//0,此时的0说明不了任何问题,并不是我们成功释放内存,也不会打印dealloc中的语句

//        ③在方法中不当的使用了retain

//        Car *car2=[Car new];

//        [car2 run:car2];//我们将 car2 自己作为参数传进去run方法,然后在run方法的内部retain,那么car2->retainCount=2,所以说这里如果只release是不够的,应该release两次才能释放完内存

}

return 0;

}

———————————————————————————————————————————

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-10 17:13:34

Objective-C 【单个对象内存管理】的相关文章

单个对象内存管理

前文我们已经说了内存管理的原则:只要出现了new alloc retain ,就一定会配对出现一个release,autorelease 那么当我一个对象被释放之后,如果我们再次调用这个对象的方法(包括这个对象的retain release方法),将会出现 野指针 错误,在xcode中具体表现为 EXC_BAD_ACCESS:访问了不可访问的内存空间,就会导致这个错误. 下面这个例子#import <Foundation/Foundation.h> int main (int argc, co

Objective-C 【多个对象内存管理(野指针&amp;内存泄漏)】

------------------------------------------- 多个对象内存管理(野指针&内存泄漏) (注:这一部分知识请结合"单个对象内存管理"去理解) 这一部分的知识比较简单,就牵扯到一个会产生野指针的情形和如何避免内存泄漏问题. 代码: #import <Foundation/Foundation.h> @interface Car : NSObject -(void)run; @end @implementation Car //监控

Objective -C Memory Management 内存管理 第一部分

Objective -C Memory Management??内存管理??第一部分 Memory management is part of a more general problem in programming called resource management. 内存管理是资源管理的一部分. Every computer system has finite resources for your program to use. These include memory, open fi

Unit03 - 对象内存管理 、 继承的意义(上)

Unit03 - 对象内存管理 . 继承的意义(上) 1.内存管理:由JVM来管理的  1)堆:    1.1)存储所有new出来的对象(包含成员变量)    1.2)没有任何引用所指向的对象就是垃圾,        垃圾回收器(GC)不定时清理垃圾,        回收过程是透明的(看不到的),        调用System.gc()建议GC尽快来回收    1.3)成员变量的生命周期:          创建对象时存在堆中,对象被回收时一并被回收    1.4)内存泄露:不再使用的对象没有

黑马程序员---OC基础7【ARC概念】【ARC对象内存管理】【分类Category】

------- iOS培训.Android培训.Java培训.期待与您交流! ---------- [ARC概念]   1.指针的分类 1)强指针,默认的情况下,所有的指针都是强指针,关键字strong: 2)弱指针,_ _weak关键字修饰符的指针 2.ARC概念 自动引用计数 永远不要写retain和release.autorelease三个关键字 编译器会在编译的时候自动插入retain和release.autorelease, 是一个编译器的特性:“垃圾回收”是运行时的特性 3.ARC工

【cocos2d-x 3.x 学习笔记】对象内存管理

内存管理 内存管理一直是一个不易处理的问题,开发者必须考虑分配回收的方式和时机,针对堆和栈做不同的优化处理,等等.内存管理的核心是动态分配的对象必须保证在使用完毕后有效地释放内存,即管理对象的生命周期.由于C++是一个较为底层的语言,其设计上不包含任何智能管理内存的机制.一个对象在使用完毕后必须被回收,然而在复杂的程序中,对象所有权在不同程序片段间传递或共享,使得确定回收的时机十分困难,因此内存管理成为了程序员十分头疼的问题. 另一方面,过于零散的对象分配回收可能导致堆中的内存碎片化,降低内存的

Objective-C(内存管理)

引用计数器 每个OC对象都有一个占4个字节存储空间的引用计数器 当使用或创建一个对象时,新对象的引用计数器默认是1 retain:可以使引用计数器+1 release:可以是引用计数器-1 retainCount:获得当前的引用计数器的值 当对象被销毁时,会重写dealloc方法 -(void)dealloc { // 这句必须放在最后面 [super dealloc]; } 僵尸对象:所占内存已经被回收的对象,僵尸对象不能再使用 野指针:指向僵尸对象(不可用的内存)的指针 错误:EXC_BAD

oc44--多对象内存管理

// Room.h #import <Foundation/Foundation.h> @interface Room : NSObject @property int no;// 房间号 @end // Room.m #import "Room.h" @implementation Room - (void)dealloc { NSLog(@"%s no = %i", __func__, _no); [super dealloc]; } @end //

oc45--多对象内存管理 优化

// // main.m // Set方法的内存管理 #import <Foundation/Foundation.h> #import "Person.h" #import "Room.h" int main(int argc, const char * argv[]) { @autoreleasepool { // 1.创建两个对象 Person *p = [[Person alloc] init]; Room *r = [[Room alloc]