Objective-C —内存管理(上)
内存管理
一、为什么要进行内存管理
移动设备的内存极其有限,每个app所能占用的内存是有限制的
下列行为都会增加一个app的内存占用
创建一个OC对象
定义一个变量
调用一个函数或者方法内存占用多大
当app所占用的内存较多时,系统会发出内存警告,这时得回收一些不需要再使用的内存空间。比如回收一些不需要使用的对象、变量等如果app占用内存过大,系统可能会强制关闭app, 造成闪退现象, 影响用户体验
二、内存分类
- 栈 :由编译器自动分配释放
- 堆 :一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收
- 全局区(静态区):
全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域
未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。
程序结束释放 - 常量区:另外还有一个专门放常量的地方, 程序结束释放
- 代码区:存放二进制代码
三、内存管理
如何回收那些不需要再使用的对象?
那就得学会OC的内存管理所谓内存管理, 就是对内存进行管理, 涉及的操作有:
分配内存 : 比如创建一个对象, 会增加内存占用
清除内存 : 比如销毁一个对象, 能减小内存占用内存管理的管理范围
任何继承了NSObject的对象
对其他非对象类型无效(int、char、float、double、struct、enum等 )只有OC对象才需要进行内存管理的本质原因
OC对象存放于堆里面
非OC对象一般放在栈里面(栈内存会被系统自动回收)
四、堆和栈
堆和栈的区别:(借用网上的一个很好的比喻)
- 使用栈就象我们去饭馆里吃饭,只管点菜(发出申请)、付钱、和吃(使用),吃饱了就走,不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,他的好处是快捷,但是自由度小。
- 使用堆就象是自己动手做喜欢吃的菜肴,比较麻烦,但是比较符合自己的口味,而且自由度大。 (经典!)
代码示例
int main(int argc, const char * argv[])
{
@autoreleasepool {
int a = 10; // 栈
int b = 20; // 栈
// c : 栈
// Car对象(计数器==1) : 堆
Car *c = [[Car alloc] init];
}
// 经过上面的代码后, 栈里面的变量a\b\c都会被回收
// 但是堆里面的Car对象还会留在内存中, 因为它是计数器依然是1
return 0;
}
五、引用计数器
- 系统是如何判断 什么时候需要回收一个对象所占用的内存?
根据对象的引用计数器
5.1什么是引用计数器
每个OC对象都有自己的引用计数器,由oc对象内部4个字节存储空间来存放
它是一个整数
从字面上, 可以理解为”对象被引用的次数”
也可以理解为: 它表示有多少人正在用这个对象简单来说, 可以理解为: 引用计数器表示有多少人正在使用这个对象
5.2根据引用计数器来确定是否回收对象
当没有任何人使用这个对象时, 系统才会回收这个对象, 也就是说:
当对象的引用计数器为0时, 对象占用的内存就会被系统回收
如果对象的计数器不为0,那么在整个程序运行过程,它占用的内存就不可能被回收(除非整个程序已经退出 )
所以我们以后就是通过操作引用计数器来管理内存任何一个对象, 刚生下来的时候, 引用计数器都为1
当使用alloc、new或者copy创建一个对象时,对象的引用计数器默认就是1
5.3操作引用计数器
要想管理对象占用的内存, 就得学会操作对象的引用计数器
- 引用计数器的常见操作
给对象发送一条retain消息, 可以使引用计数器值+1(retain方法返回对象本身)
给对象发送一条release消息, 可以使引用计数器值-1
给对象发送retainCount消息, 可以获得当前的引用计数器值
需要注意的是: release并不代表销毁\回收对象, 仅仅是计数器-1
六、delloc方法
delloc方法调用
当一个对象的引用计数器值为0时
这个对象即将被销毁,其占用的内存被系统回收
系统会自动给对象发送一条dealloc消息
(因此, 从dealloc方法有没有被调用, 就可以判断出对象是否被销毁)dealloc方法的重写
一般会重写dealloc方法, 在这里释放相关资源, dealloc就是对象的遗言
一旦重写了dealloc方法, 就必须调用[super dealloc],并且放在最后面调用- (void)dealloc
{
NSLog(@"Person ---- dealloc----"); // 必须调用, 必须放在最后面
[super dealloc];
}
使用注意
不能直接调用dealloc方法
一旦对象被回收了, 它占用的内存就不再可用, 坚持使用会导致程序崩溃(野指针错误)
七、空指针、野指针
僵尸对象
已经被销毁的对象(不能再使用的对象)野指针
指向僵尸对象(不可用内存/坏内存)的指针
给野指针发消息会报EXC_BAD_ACCESS错误空指针
没有指向存储空间的指针(里面存的是nil, 也就是0)
给空指针发消息是没有任何反应的为了避免野指针错误的常见办法
在对象被销毁之后, 将指向对象的指针变为空指针
八Xocde设置
要手动管理oc对象内存,需要在xcode中进行一下设置
- 关闭ARC功能,才能手动调用retain、release等方法
- 开启僵尸对象监控,默认情况下,Xcode是不会管僵尸对象的,使用一块被释放的内存也不会报错。为了方便调试,应该开启僵尸对象监控
九、内存管理原则
9.1 多对象内存管理
单个对象的内存管理, 看起来非常简单
如果对多个对象进行内存管理, 并且对象之间是有联系的, 那么管理就会变得比较复杂
其实, 多个对象的管理思路 跟 很多游戏的房间管理差不多
比如斗地主 \ QQ堂总的来说, 有这么几点管理规律
只要还有人在用某个对象,那么这个对象就不会被回收
只要你想用这个对象,就让对象的计数器+1
当你不再使用这个对象时,就让对象的计数器-1
9.2 内存管理原则
苹果官方规定的内存管理原则
谁创建谁release : 如果你通过alloc、new或[mutable]copy来创建一个对象,那么你必须调用release或autorelease谁retain谁release :只要你调用了retain,就必须调用一次release
总结一下就是
有加就有减
曾经让对象的计数器+1,就必须在最后让对象计数器-1
9.3 set方法的内存管理
set方法
- (void)setCar:(Car *)car
{
if (car != _car)
{
// 对当前正在使用的车(旧车)做一次release
[_car release];
// 对新车做一次retain操作
_car = [car retain];
}
}
9.4 dealloc方法的内存管理
dealloc方法
- (void)dealloc
{
// 当人不在了,代表不用车了
// 对车做一次release操作
[_car release];
[super dealloc];
}
Objective-C —内存管理(上)的更多相关文章
- 垃圾回收GC:.Net自己主动内存管理 上(一)内存分配
垃圾回收GC:.Net自己主动内存管理 上(一)内存分配 垃圾回收GC:.Net自己主动内存管理 上(一)内存分配 垃圾回收GC:.Net自己主动内存管理 上(二)内存算法 垃圾回收GC:.Net自己 ...
- C语言堆内存管理上出现的问题,内存泄露,野指针使用,非法释放指针
C语言堆内存管理上出现的问题,内存泄露,野指针使用,非法释放指针 (1)开辟的内存没有释放,造成内存泄露 (2)野指针被使用或释放 (3)非法释放指针 (1)开辟的内存没有释放.造成内存泄露,以下的样 ...
- Objective C内存管理之理解autorelease------面试题
Objective C内存管理之理解autorelease Autorelease实际上只是把对release的调用延迟了,对于每一个Autorelease,系统只是把该Object放入了当前的A ...
- 垃圾回收GC:.Net自己主动内存管理 上(二)内存算法
垃圾回收GC:.Net自己主动内存管理 上(二)内存算法 垃圾回收GC:.Net自己主动内存管理 上(一)内存分配 垃圾回收GC:.Net自己主动内存管理 上(二)内存算法 垃圾回收GC:.Net自己 ...
- 垃圾回收GC:.Net自己主动内存管理 上(三)终结器
垃圾回收GC:.Net自己主动内存管理 上(三)终结器 垃圾回收GC:.Net自己主动内存管理 上(一)内存分配 垃圾回收GC:.Net自己主动内存管理 上(二)内存算法 垃圾回收GC:.Net自己主 ...
- Objective C 内存管理[转]
1 配对原则 alloc – release new – release retain - release copy – release 2 new和alloc-init的区别 (1)区别只在于a ...
- objective C 内存管理及属性方法具体解释
oc为每一个对象提供一个内部计数器.这个计数器跟踪对象的引用计数,当对象被创建或拷贝时.引用计数为1.每次保持对象时,调用retain接口.引用计数加1.假设不需要这个对象时调用release,引用计 ...
- Linux内存管理之地址映射
写在前面:由于地址映射涉及到各种寄存器的设置访问,Linux对于不同体系结构处理器的地址映射采用不同的方法,例如对于i386及后来的32位的Intel的处理器在页式映射时采用的是2级页表映射,而对于I ...
- [基础] C++与JAVA的内存管理
在内存管理上(总之一句话——以后C++工程,一定要用智能指针!) 1.同是new一个对象,C++一定得手动delete掉,而且得时刻记住能delete的最早时间(避免使用空指针).JAVA可以存活于作 ...
- GC与显式内存管理
C++复兴的话题至今已被鼓吹两年有余,Herb Sutter和Bjarne Stroustrup等大牛们也为C++带来了大步伐的革新.然而,从这两年的效果而言,C++的复兴并没有发生.一方面随着世界经 ...
随机推荐
- yarn架构——本质上是在做解耦 将资源分配和应用程序状态监控两个功能职责分离为RM和AM
Hadoop YARN架构解读 原Mapreduce架构 原理架构图如下: 图 1.Hadoop 原 MapReduce 架构 原 MapReduce 程序的流程:首先用户程序 (JobClient) ...
- Caused by: java.lang.NoClassDefFoundError: org/apache/neethi/AssertionBuilderFactory
转自:https://blog.csdn.net/iteye_8264/article/details/82641058 1.错误描述 严重: StandardWrapper.Throwable or ...
- luogu 1593 因子和
因子和 题目描述 输入两个正整数a和b,求\(a^b\)的因子和.结果太大,只要输出它对9901的余数. 解法 基本算数定理,每一个数都可以被分解成一系列的素数的乘积,然后你可以分解出因数了. 如何求 ...
- ROS常用知识指南
前言:介绍一些基础常用的知识. 一.标准单位 二.坐标表现方式 三.默认安装位置 通过apt-get安装的软件包, 默认安装位置为:/opt/ros/kinetic/share 四.软件包安装流程 4 ...
- javascript中常用数组方法详细讲解
javascript中数组常用方法总结 1.join()方法: Array.join()方法将数组中所以元素都转化为字符串链接在一起,返回最后生成的字符串.也可以指定可选的字符串在生成的字符串中来分隔 ...
- python模拟登陆知乎
---恢复内容开始--- 在完成前面的阶段的任务之后,我们现在已经能够尝试着去模拟登录一些网站了.在这里我们模拟登录一下知乎做一下实验.笔者在这里总共用了三天多的时间,下面给大家分享一下笔者是怎么一步 ...
- 关于CR0寄存器
开始的时候,我认为CR0.WP如果被置位,那么内存的页面只读属性将会失效,导致可以被写入数据. 这几天正好碰到一个问题,查看了资料才发现,之前的理解不完整. 引用Intel手册中的一句话: CR0.W ...
- ABBYY简体中文版终身授权半价来袭,真的是5折!
经过了一个春秋,心心念念的双十一终于要来了,一年时间并不长,但这一个月尤其慢!ABBYY官方称为回馈广大用户的支持与厚爱,双十一期间,ABBYY价格感人,诱惑难挡. 说到双十一活动,方式也是五花八门, ...
- 第六章 Python之迭代器与生成器
迭代器 迭代:迭代是一个重复的过程,每次重复即一次迭代,并且每次迭代的结果是下一次重复的初始值 l=['a','b','c'] count=0 while count < len(l): pri ...
- 转:用java调用oracle存储过程总结(比较好理解)
这段时间开始学习写存储过程,主要原因还是因为工作需要吧,本来以为很简单的,但几经挫折,豪气消磨殆尽,但总算搞通了,为了避免后来者少走弯路,特记述与此,同时亦对自己进行鼓励. 一:无返回值的存储过程 存 ...