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;
}
———————————————————————————————————————————
版权声明:本文为博主原创文章,未经博主允许不得转载。
Objective-C 【单个对象内存管理(野指针&内存泄露)】的更多相关文章
- Objective-C 【多个对象内存管理(野指针&内存泄漏)】
------------------------------------------- 多个对象内存管理(野指针&内存泄漏) (注:这一部分知识请结合"单个对象内存管理"去 ...
- C#高级编程9 第14章 内存管理和指针
C#高级编程9 内存管理和指针 后台内存管理 1) 值数据类型 在处理器的虚拟内存中有一个区域,称为栈,栈存储变量的浅副本数据,通过进入变量的作用域划分区域,通过离开变量的作用域释放. 栈的指针指向栈 ...
- Rust语言——无虚拟机、无垃圾收集器、无运行时、无空指针/野指针/内存越界/缓冲区溢出/段错误、无数据竞争
2006年,编程语言工程师Graydon Hoare利用业余时间启动了Rust语言项目.该项目充分借鉴了C/C++/Java/Python等语言的经验,试图在保持良好性能的同时,克服以往编程语言所存在 ...
- JVM自动内存管理机制——Java内存区域(下)
一.虚拟机参数配置 在上一篇<Java自动内存管理机制——Java内存区域(上)>中介绍了有关的基础知识,这一篇主要是通过一些示例来了解有关虚拟机参数的配置. 1.Java堆参数设置 a) ...
- 垃圾回收GC:.Net自己主动内存管理 上(一)内存分配
垃圾回收GC:.Net自己主动内存管理 上(一)内存分配 垃圾回收GC:.Net自己主动内存管理 上(一)内存分配 垃圾回收GC:.Net自己主动内存管理 上(二)内存算法 垃圾回收GC:.Net自己 ...
- 垃圾回收GC:.Net自己主动内存管理 上(二)内存算法
垃圾回收GC:.Net自己主动内存管理 上(二)内存算法 垃圾回收GC:.Net自己主动内存管理 上(一)内存分配 垃圾回收GC:.Net自己主动内存管理 上(二)内存算法 垃圾回收GC:.Net自己 ...
- Win3内存管理之私有内存跟共享内存的申请与释放
Win3内存管理之私有内存跟共享内存的申请与释放 一丶内存简介私有内存申请 通过上一篇文章.我们理解了虚拟内存与物理内存的区别. 那么我们有API事专门申请虚拟内存与物理内存的. 有私有内存跟共享内存 ...
- Linux中的Buffer Cache和Page Cache echo 3 > /proc/sys/vm/drop_caches Slab内存管理机制 SLUB内存管理机制
Linux中的Buffer Cache和Page Cache echo 3 > /proc/sys/vm/drop_caches Slab内存管理机制 SLUB内存管理机制 http://w ...
- 七.OC基础加强--1.内存管理 2.野指针,内存泄露 3.set方法的内存管理 4.@property参数 5.@class和循环retain的使用 6.NSString的内存管理
1,内存管理简单介绍 1,为什么要有内存管理? malloc selloc dealloc```需要回头复习 一般的内存 4s 是512m内存:6 是1024m内存: 当内存过大时,会耗尽内存.出现程 ...
随机推荐
- IOC运用到MVC中
IOC可以摒弃掉类中类的紧耦合,让设计和重用更简单,将IOC加入到MVC中的实现非常简单,那么有哪几种方法?它们的实现又是什么原理呢? IOC在MVC中的注入,主要是在获取Controller对象中实 ...
- BZOJ 1005: [HNOI2008]明明的烦恼 Purfer序列 大数
1005: [HNOI2008]明明的烦恼 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/ ...
- C# 采用线程重绘图形要点记录
大家都知道J2ME 采用一个线程去获取数据,然后得到数据后更新屏幕是件很容易的事情,比如Thread{public void run(){ getData();repaint(); } }这样做就OK ...
- UEditor-JSP版部署说明
昨天项目中需要在UEditor用到图片上传功能,于是昨天中午便开始做这一块的整合,一不小心就弄到了现在, 坑还挺多的,比如一开始一直报ActionEnter cannot be resolved to ...
- [ZZ]C++中,引用和指针的区别
(1) 引用总是指向一个对象,没有所谓的 null reference .所有当有可能指向一个对象也由可能不指向对象则必须使用 指针. 由于C++ 要求 reference 总是指向一个对象所以 re ...
- 1050. String Subtraction (20)
this problem is from PAT, which website is http://pat.zju.edu.cn/contests/pat-a-practise/1050. firs ...
- dl-ssl.google.com
转载:http://jingyan.baidu.com/article/64d05a02752300de55f73b99.html 搭建Android就会用到Android SDK,而安装SDK有个恶 ...
- Linux 学习笔记 文件权限
* Linux系统会为各种各样的功能创建不同的用户账户,而这些账户并不是真的用户.这些账户称作系统账户,是系统上运行的各种服务进程访问资源用的特殊账户. 所有运行在后台的服务都需要用一个系统用户账户登 ...
- Java用筛子法求素数
描述现在给出你一些数,要求你写出一个程序,输出这些整数相邻最近的素数,并输出其相距长度.如果左右有等距离长度素数,则输出左侧的值及相应距离.如果输入的整数本身就是素数,则输出该素数本身,距离输出0 ...
- javascript 关于语义化作用的理解
看代码实例1 var a=1; function m(a){ //此处为形参第一个传入函数的参数,既为arguments[0] alert(a); //此处a为与形参绑定的 } m(a);//1 此时 ...