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

单个对象内存管理



(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 【单个对象内存管理(野指针&内存泄露)】的更多相关文章

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

    ------------------------------------------- 多个对象内存管理(野指针&内存泄漏) (注:这一部分知识请结合"单个对象内存管理"去 ...

  2. C#高级编程9 第14章 内存管理和指针

    C#高级编程9 内存管理和指针 后台内存管理 1) 值数据类型 在处理器的虚拟内存中有一个区域,称为栈,栈存储变量的浅副本数据,通过进入变量的作用域划分区域,通过离开变量的作用域释放. 栈的指针指向栈 ...

  3. Rust语言——无虚拟机、无垃圾收集器、无运行时、无空指针/野指针/内存越界/缓冲区溢出/段错误、无数据竞争

    2006年,编程语言工程师Graydon Hoare利用业余时间启动了Rust语言项目.该项目充分借鉴了C/C++/Java/Python等语言的经验,试图在保持良好性能的同时,克服以往编程语言所存在 ...

  4. JVM自动内存管理机制——Java内存区域(下)

    一.虚拟机参数配置 在上一篇<Java自动内存管理机制——Java内存区域(上)>中介绍了有关的基础知识,这一篇主要是通过一些示例来了解有关虚拟机参数的配置. 1.Java堆参数设置 a) ...

  5. 垃圾回收GC:.Net自己主动内存管理 上(一)内存分配

    垃圾回收GC:.Net自己主动内存管理 上(一)内存分配 垃圾回收GC:.Net自己主动内存管理 上(一)内存分配 垃圾回收GC:.Net自己主动内存管理 上(二)内存算法 垃圾回收GC:.Net自己 ...

  6. 垃圾回收GC:.Net自己主动内存管理 上(二)内存算法

    垃圾回收GC:.Net自己主动内存管理 上(二)内存算法 垃圾回收GC:.Net自己主动内存管理 上(一)内存分配 垃圾回收GC:.Net自己主动内存管理 上(二)内存算法 垃圾回收GC:.Net自己 ...

  7. Win3内存管理之私有内存跟共享内存的申请与释放

    Win3内存管理之私有内存跟共享内存的申请与释放 一丶内存简介私有内存申请 通过上一篇文章.我们理解了虚拟内存与物理内存的区别. 那么我们有API事专门申请虚拟内存与物理内存的. 有私有内存跟共享内存 ...

  8. 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 ...

  9. 七.OC基础加强--1.内存管理 2.野指针,内存泄露 3.set方法的内存管理 4.@property参数 5.@class和循环retain的使用 6.NSString的内存管理

    1,内存管理简单介绍 1,为什么要有内存管理? malloc selloc dealloc```需要回头复习 一般的内存 4s 是512m内存:6 是1024m内存: 当内存过大时,会耗尽内存.出现程 ...

随机推荐

  1. 函数定义从零开始学C++之从C到C++(一):const与#define、结构体对齐、函数重载name mangling、new/delete 等

    今天一直在学习函数定义之类的问题,下午正好有机会和大家共享一下. 一.bool 类型 逻辑型也称布尔型,其取值为true(逻辑真)和false(逻辑假),存储字节数在不同编译系统中可能有所不同,VC+ ...

  2. poj 1338 Ugly Numbers(丑数模拟)

    转载请注明出处:viewmode=contents">http://blog.csdn.net/u012860063? viewmode=contents 题目链接:id=1338&q ...

  3. android圆角View实现及不同版本这间的兼容(android3.0过后的版本)

    http://blog.csdn.net/lovecluo/article/details/8710174 在做我们自己的APP的时候,为了让APP看起来更加的好看,我们就需要将我们的自己的View做 ...

  4. C++11 新特性之 Lambda表达式

    lambda表达式能够用于创建并定义匿名的函数对象,以简化编程工作 Lambda的语法例如以下: [函数对象參数](操作符重载函数參数)->返回值类型{函数体} []内的參数指的是Lambda表 ...

  5. SAP BW 通过视图创建数据源(无单位)

    因业务明细表中数量没有单位,所以BW创建数据源时,需做增强 数据表: ZDB_H(抬头) ZDB_I(明细) ECC 系统中: 1.创建视图ZVDBWQ,因明细表中数量没有单位,所以创建视图时不包括数 ...

  6. Hadoop发展历史简介

    简介 本篇文章主要介绍了Hadoop系统的发展历史以及商业化现状, 科普文. 如果你喜欢本博客,请点此查看本博客所有文章:http://www.cnblogs.com/xuanku/p/index.h ...

  7. printf, fprintf, sprintf, snprintf, vprintf, vfprintf, vsprintf, vsnprintf - 输出格式转换函数

    参考:http://blog.sina.com.cn/s/blog_674b5aae0100prv3.html 总览 (SYNOPSIS) #include <stdio.h> int p ...

  8. eclipse ctrl+左击不能关联相应文件

    <?xml version="1.0" encoding="UTF-8"?><projectDescription> <name& ...

  9. Swiper Usage&&API

    最近使用Swipe.js,发现中文的资料很少,试着翻译了一下.能力有限,翻译难免错漏,请指出,多谢!如果想获得国外较多而全的文档,还是用google. 一了解SwiperSwiper 是一款免费以及轻 ...

  10. PHP对大文件的处理思路

    需求: 现有一个1G左右的日志文件,大约有500多万行, 用php返回最后几行的内容. 在php中,对于文件的读取时,最快捷的方式莫过于使用一些诸如file.file_get_contents之类的函 ...