1.什么是内存管理

  • 移动设备的内存极其有限,每个app所能占用的内存是有限制的
  • 当app所占用的内存较多时,系统会发出内存警告,这时得回收一些不需要再使用的内存空间。比如回收一些不需要使用的对象、变量等
  • 管理范围:任何继承了NSObject的对象需要去管理内存,但是对于对其他基本数据类型(int、char、float、double、struct、enum等)结构,枚举等不用去关心内存
- (void)test
{
int a = 2;
int b = 1; Person *person = [[Person alloc] init]; // 方法未退出之前 这三行代码在内存中如图
}

一旦test方法执行完毕,意味着局部变量的作用域也失效,那么栈空间的局部变量系统会自动检测回收。但是堆空间中动态产生的对象是还没有被回收。如图

可以看出即使已经没有指针指向动态产生的对象了,但还是没有被回收,因此需要手动管理释放。释放的方法是为对象发送一条消息。因此需要调用对象的某个方法来释放对象。

那么系统是怎么知道此时的对象需不需要回收呢?这就涉及到了对象结构中的"引用计数"

2.对象结构

  • 每个OC对象内部都有自己的引用计数器,它是一个整数,表示"对象被引用的次数",即有多少人正在使用这个OC对象
  • 每个OC对象内部会自动设置4个字节的存储空间来存储引用计数器

3.引用计数器的作用

  • 当使用alloc、new或者copy创建一个新对象时,新对象的引用计数器默认就是1
  • 当一个对象的引用计数器值为0时,对象占用的内存就会被系统回收。换句话说,如果对象的计数器不为0,那么在整个程序运行过程,它占用的内存就不可能被回收,除非整个程序已经退出

4.操作对象引用计数器的方法

  • 给对象发送一条retain消息,可以使引用计数器值+1(retain方法返回对象本身)retain方法返回的是id类型,那么哪个对象调用返回的就是自己
  • 给对象发送一条release消息,可以使引用计数器值-1
  • 可以给对象发送retainCount消息获得当前的引用计数器值

 5.对象的销毁

  • 当一个对象的引用计数器值为0时,那么它将被销毁,其占用的内存被系统回收
  • 当一个对象被销毁时,系统会自动向对象发送一条dealloc消息
  • 一般会重写dealloc方法,在这里释放相关资源,dealloc就像对象的遗言
  • 一旦重写了dealloc方法,就必须调用[super dealloc],并且放在最后面调用
  • 不能直接调用dealloc方法
  • 一旦对象被回收了,它占用的内存就不再可用,坚持使用会导致程序崩溃(野指针错误)
    // alloc方法是给堆中分配内存 init方法和内存无关 此时retainCurrent为1
Person *p = [[Person alloc] init]; // 返回的就是对象本身 retainCurrent为2
[p retain]; // retainCurrent为1
[p release]; // retainCurrent为0 说明Person类对象被回收,那么对应的在内存中的地址已经不可用了 此时的Person对象称为“僵尸对象”但是此时p指针还是在指向Person类对象所对应的那块不可用的地址此时的p指针称为“野指针”
[p release];

 6.开发中要注意的内存管理

默认情况下,Xcode是不会管理僵尸对象的,即使使用了一块被释放的内存也不会报错。为了方便调试,应该开启僵尸对象监控。如图设置:

注意三个概念:

僵尸对象:已经被回收的对象,或者说对象所对应的内存地址已经不可用的对象称为僵尸对象。僵尸对象不可用

野指针:指向一块不可用内存地址或者指向僵尸对象的指针称为野指针。给野指针发送消息会报 EXC_BAD_ACCESS错误

空指针:没有指向任何指针变量称为空指针,也意味着指针变量所存储的值为0,nil,NULL 这样可以避免野指针错误的发生

/********************************** Person.h **************************************/
#import <Foundation/Foundation.h> @interface Person : NSObject @property int age; @end /********************************** Person.m **************************************/
#import "Person.h" @implementation Person // 重写父类NSOjbct的遗言方法 对象在被释放之前一定会调用dealloc方法 - (void)dealloc
{
NSLog(@"对象在释放之前会执行遗言方法被执行"); [super dealloc]; // 一定要调用 而且必须放在最后面
}
@end /********************************** main.m **************************************/
#import <Foundation/Foundation.h>
#import "Person.h" /*
main方法是一个死循环方法以保证程序能持续运行,除非用户关闭程序或者是手机没电,程序才能终止
那么在main方法里面的Person对象不就一直存在么,因此必须在main方法里面将对象回收
*/
int main(int argc, const char * argv[])
{
// alloc方法是给堆中分配内存 init方法和内存无关 此时retainCurrent为1
Person *p = [[Person alloc] init]; // 返回的就是对象本身 retainCurrent为2
[p retain]; // retainCurrent为1
[p release]; /*
retainCurrent为0
说明Person类对象被回收,那么对应的在内存中的地址已经不可用了
此时的Person对象称为“僵尸对象”
此时p指针还是在指向Person类对象所对应的那块不可用的地址,此时p指针称为“野指针”
*/
[p release]; /*
对象已经被回收,千万别以为再给对象发送一个retain消息对象就可以“起死回生”应该节哀顺变
执行retain方法会报错,此时的p指针已称为野指针执行代码回报:野指针错误
*/ // [p retain]; /*
此时对象已经被回收称为“僵尸对象了”不可以再访问属性
在执行p.age = 10;报错:
-[Person setAge:]: message sent to deallocated instance 消息发送给了已经被释放的对象
再次证明“僵尸对象不可以用”
*/ /*
一旦指针成为野指针再继续向p指针所指的对象发送消息就会报错:Exc_BAd_ACCESS
说明访问了一块坏内存(已经被回收、不可用的内存) “野指针错误”
那么此时在对象回收之后将指针变量清空
那么栈中的指针变量就不会再指向堆中类对象的内存地址了
*/
p = nil; /*
指针变量内部所存储的值已被清空,那么指针已经无指向
再给指针发送任何消息指针会无任何响应,而且也不报错因为OC中没有空指针错误
*/
[p release];
[p release];
[p release];
[p release]; return ;
}

iOS 非ARC基本内存管理系列 1-引用计数器的更多相关文章

  1. iOS 非ARC基本内存管理系列 -手把手教你ARC——iOS/Mac开发ARC入门和使用(转)

    手把手教你ARC——iOS/Mac开发ARC入门和使用 Revolution of Objective-c 本文部分实例取自iOS 5 Toturail一书中关于ARC的教程和公开内容,仅用于技术交流 ...

  2. iOS 非ARC基本内存管理系列 2-多对象内存管理(3) 利用@property来自动管理内存

    iOS 基本内存管理-多对象内存管理(2)中可以看到涉及到对象的引用都要手动管理内存:每个对象都需要写如下代码 // 1.对要传入的"新车"对象car和目前Person类对象所拥有 ...

  3. iOS 非ARC基本内存管理系列总结6 -设计微博模型

    设计简单的微博模型:用User类和Status类来模拟实现 在非ARC机制下有两种方式,两者没有太大的区别之所以写了两种只是为了方便学习和对比两种写法! 第一种:没有使用atuorelease和自动释 ...

  4. iOS 非ARC基本内存管理系列 4-autorelease方法和@autoreleasepool

    1.autorelease 基本用法 对象执行autorelease方法时会将对象添加到自动释放池中 当自动释放池销毁时自动释放池中所有对象作release操作 对象执行autorelease方法后自 ...

  5. iOS 非ARC基本内存管理系列 2-多对象内存管理(2)

    /* 多对象内存管理: 以人拥有车为例涉及到@property底层set方法管理内存的实现 注意:人在换车的时候要进行当前传入的车和人所拥有的车进行判断 */ /******************* ...

  6. iOS 非ARC基本内存管理系列 2-多对象内存管理(1)

    单个对象的内存管理非常简单无非就是alloc对应release,retain对应release.但是如果涉及到很多对象,而且对象与对象有联系的时候该怎么去管理对象的内存呢. 比如同样一本书有好3个人购 ...

  7. iOS 非ARC基本内存管理系列 5-autorelease方法使用总结

    autorelase:可以将对象交给自动释放池中,释放池销毁的时候对里面的对象做一次release操作代码如下 @autoreleasepool { Person *person = [[[Perso ...

  8. iOS 非ARC基本内存管理系列 3-循环retain和@class

    1.@class 使用场景:对于循环依赖关系来说,比方A类引用B类,同时B类也引用A类: 可以看出Person和Card互相引用,此时如果使用#import编译报错!因此当使用@class在两个类中相 ...

  9. IOS 非ARC开发内存管理的几条规则

    关于ios内存管理.在开发过程中,内存管理很重要,我简单说明一下. 1.正确用法 UIView *v = [[UIView alloc] init]; //分配后引用计数为1 [self.view a ...

随机推荐

  1. [Angular 2] Create Shareable Angular 2 Components

    Components that you use across multiple applications need to follow a module pattern that keeps them ...

  2. android service总结

    1.通过startservice方法启动一个服务.service不能自己启动自己.若在一个服务中启动一个activity则,必须是申明一个全新的activity任务TASK.通过startservic ...

  3. iOS开发——Swift篇&文件,文件夹操作

    文件,文件夹操作   ios开发经常会遇到读文件,写文件等,对文件和文件夹的操作,这时就可以使用NSFileManager,NSFileHandle等类来实现. 下面总结了各种常用的操作:   1,遍 ...

  4. android150 笔记

    1. 什么是Activity? 四大组件之一,一般的,一个用户交互界面对应一个activity,界面的容器. setContentView() ,// 要显示的布局 button.setOnclick ...

  5. yum服务器设置

    转自:http://blog.chinaunix.net/uid-22141042-id-1789605.html 不得不说,RedHat的确很邪恶,如果我们直接用他自带的系统碟做YUM源的话,总是会 ...

  6. LibSVM学习(四)——逐步深入LibSVM 转

    原文:http://blog.csdn.net/flydreamgg/article/details/4470121 其实,在之前上海交大模式分析与机器智能实验室对2.6版本的svm.cpp做了部分注 ...

  7. java_有返回值线程_提前加载例子

    package com.demo.test3; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionE ...

  8. Web Navigation

    Description Standard web browsers contain features to move backward and forward among the pages rece ...

  9. Android(java)学习笔记77:网络编程的概述

    计算机网络 是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统,网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递的计算机系统. 网络编程 就 ...

  10. APK文件安装模拟器和ADB命令的使用

    1.安装APK文件到模拟器 Android手机使用的执行文件为APK格式,类似于Windows平台的exe文件.在Android模拟器中安装APK文件有多种方法,如果你是开发人员,可以通过Eclips ...