A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

彭智林老师

初级黑马

  • 黑马币:26

  • 帖子:12

  • 精华:0

© 彭智林老师 初级黑马   /  2016-5-25 01:46  /  7010 人查看  /  29 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 彭智林老师 于 2016-5-25 08:41 编辑

           哈喽,大家好,我是深圳双元课堂的iOS导师--彭智林老师,我觉得我们每一个来到黑马的老师或者学生,都在这苦逼的路上逗逼的奔向牛逼,因为我们每一天都在努力,每一天都在进步,每一天都在用心,每天都在严格要求自己,而且人生嘛,只有拼出来的精彩,绝无等待出来的辉煌,所以我们首先呢我们应该向自己和身边的每一个努力的小伙伴致敬对不对?。接下来呢,我给大家分享一点知识,我最近和学生交流,发现部分同学对野指针和空指针、内存泄露这块理解起来有点费劲,其实这块不难,这个地方呢概念比较多,所以只是需要大家花点时间理解,那么如果现在还有不明白的呢,我给大家做了一个简单的总结,大家可以参考一下,希望会有点帮助,咋们大家一起加油


  空指针、野指针和僵尸对象、内存泄露


   一.什么是空指针、野指针和僵尸对象、内存泄露


    1.空指针
    1> 没有存储任何内存地址的指针就称为空指针(NULL指针)  
    2> 空指针就是被赋值为0的指针,在没有被具体初始化之前,其值为0。
下面是2个代码示例
  1.   Student *s1 = NULL;

  2.   Student *s2 = nil;
复制代码

     2.  野指针
   1. C语言中的野指针: 指的是声明1个指针变量.没有为这个指针变量初始化.  
        那么这个指针变量的值就是1个垃圾值.   
        指向内存中随机的1块空间,这个指针就叫做野指针.

    2. OC中的野指针:  1个指针指向的对象已经被释放了.那么这个指针就叫做野指针

3.  僵尸对象
>  指的是一个已经被回收 但是 这个对象的数据还在内存中.
    像这样的对象就叫做僵尸对象.

4.内存泄露

"内存泄露"  (栈区的指向已经释放,  堆区的空间没有释放, 这时堆区的空间就被泄露了)
堆区,需要程序员手动管理

  •   强调

不管是多个对象还是单个对象,只要我们研究它的内存管理,就两点:

1.僵尸对象(野指针)
2.内存泄露

  二.野指针、空指针的例子


  • 以下是几个简单的例子对比一下野指针和空指针的区别  


  • 首先打开Xcode改为MRC内存管理和打开僵尸僵尸对象检测


Snip20160525_4.png Snip20160525_5.png
Snip20160525_6.png

   2. 自定义Student类,在main函数中添加下列代码
  1. int main(int argc, const char * argv[]) {
  2.     @autoreleasepool {
  3.         HMStudent *stu = [[HMStudent alloc]init];
  4.         [stu setAge:18];
  5.         [stu release];
  6.         [stu setAge:20];
  7.     }
  8.     return 0;
  9. }
复制代码
  • 运行程序,你会发现运行到[stu setAge:20]这句代码会报错,是个野指针错误

   3.接下来分析一下报错的原因
  
   1> 执行完第3行代码后,内存中有个指针变量stu,指向了HMStudent对象
  1. HMStudent *stu = [[HMStudent alloc]init];
复制代码


Snip20160525_8.png

  • 假设HMStudent对象的地址为0x10010    ,指针变量stu的地址为0xhhh045  ,stu中存储的是HMStudent对象的地址0x10010。即指针变量stu指向了这个HMStudent对象。

    2> 接下来是第4行代码
  1. [stu setAge:18];
复制代码
  这行代码的意思是:给stu所指向的HMStudent对象发送一条setAge:消息,即调用这个HMStudent对象的setAge:方法。目前来说,这个HMStudent对象仍存在于内存中,所以这句代码没有任何问题。

    3> 接下来是第5行代码
  1. [stu release];
复制代码
这行代码的意思是:给stu指向的HMStudent对象发送一条release消息。在这里,HMStudent对象接收到release消息后,会马上被销毁,所占用的内存会被回收。
HMStudent对象被销毁了,地址为0x10010的内存就变成了"垃圾内存",然而,指针变量stu仍然指向这一块内存,这时候,stu就称为了野指针!

    4> 最后执行了第6行代码
  1. [stu setAge:20];
复制代码
这句代码的意思仍然是: 给stu所指向的HMStudent对象发送一条setAge:消息。但是在执行完第5行代码后,HMStudent对象已经被销毁了,它所占用的内存已经是垃圾内存,如果你还去访问这一块内存,那就会报野指针错误。这块内存已经不可用了,也不属于你了,你还去访问它,肯定是不合法的。所以,这行代码报错了!

    4.如果改动一下代码,就不会报错
  1. #import <Foundation/Foundation.h>
  2. #import "HMStudent.h"
  3. int main(int argc, const char * argv[]) {
  4.     @autoreleasepool {
  5.         
  6.         HMStudent *stu = [[HMStudent alloc]init];
  7.         
  8.         [stu setAge:18];
  9.         
  10.         [stu release];
  11.         
  12.         stu = nil;
  13.         
  14.         [stu setAge:20];
  15.         
  16.         
  17.     }
  18.     return 0;
  19. }
复制代码
那么这个时候,stu变成了空指针,stu就不再指向任何内存了
因为stu是个空指针,没有指向任何对象,因此[stu setAge:20]消息是发不出去的,不会造成任何影响。当然,肯定也不会报错。

    5.总结
1> 利用野指针发消息是很危险的,会报错。也就是说,如果一个对象已经被回收了,就不要再去操作它,不要再尝试给它发消息。
2> 利用空指针发消息是没有任何问题的,也就是说下面的代码是没有错误的:
  1. [nil setAge:20];
复制代码
#  避免使用僵尸对象的方法
1)僵尸对象调用方法,会报错,访问成员变量有时是可以的(但是这个是未知的)。
2)为了防止不小心调用了僵尸对象,可以将对象赋值nil(对象的空值)
用nil调用方法是不会报错的。
# 对象的内存泄露的几种情况
1) retain和release不匹配,retain多余release导致的内存泄露;
2) 对象使用过程中,没有被release,而被赋值为nil;
3) 在方法中不当的使用了retain;




29 个回复

倒序浏览
干货
回复 使用道具 举报
厉害,必须赞
回复 使用道具 举报
老师把一些基本概念讲的很好,点赞{:2_30:}
回复 使用道具 举报

彬哥的C指针艺术也都是干货,学习了,必须赞
回复 使用道具 举报

彬哥的C指针艺术也都是干货,学习了,必须赞
回复 使用道具 举报 1 0

橘子哥的帖子,也狠赞
回复 使用道具 举报
王博1 发表于 2016-5-26 10:59
老师把一些基本概念讲的很好,点赞

回复 使用道具 举报
干活   赞一个
回复 使用道具 举报
虽然没看懂,但是我收到了鼓舞
回复 使用道具 举报
高大上。
回复 使用道具 举报
给力,貌似看到了植物大战僵尸的赶脚{:3_53:}
回复 使用道具 举报
大家好  过来 冒个泡
回复 使用道具 举报
厉害,有学到了精华的知识了
回复 使用道具 举报
这真是长见识啊每天都有好多知识给力
回复 使用道具 举报
好厉害的感觉
回复 使用道具 举报
赞一个66666666
回复 使用道具 举报
谢谢分享!
回复 使用道具 举报
虽然没看懂,但是我收到了鼓舞
回复 使用道具 举报
多谢老师分享经验
回复 使用道具 举报
12下一页
您需要登录后才可以回帖 登录 | 加入黑马