Objective-C学习笔记_内存管理(一)

一、内存管理的?式

大家都去过图书馆,而图书馆里的书是可以借出的。我们来设想这样一个场景,大家都去借书,但是从来没有人去还书,那么最后,这个图书馆会因为无书可借而倒闭,每个人都没法再使用图书馆。计算机也是这样,当程序运行结束时,操作系统将回收其占用的资源。但是,只要程序运行就会占用资源,如果不进行清理已经不用的资源,资源最终将被耗尽,程序将崩溃。

学会内存管理我们就明白什么时候由你释放对象,什么时候你不能释放。C语言中通过malloc、calloc、realloc和free搭配对内存进行管理。但是,C中的内存管理极易引起内存泄露和野指针异常(有关C语言内存泄露的问题,不是本博文的重点,对此不做过多赘述。详情会在后续的博文中专门讲解C内存问题。),而Objective-C对此进行了优化。

iOS应用程序出现Crash(闪退),90%以上的原因是内存问题。在一个拥有数?个甚至是上百个类的工程里,查找内存问题极其困难。了解内存常见问题,能帮我们减少出错几率。内存问题体现在两个?面:内存溢出、野指针异常。

内存溢出

iOS给每个应?程序提供了一定的内存,?于程序的运行。iPhone 3GS内存30M左右,iPhone 5S内存80M左右。一旦超出内存上限,程序就会Crash。程序中最占内存的就是图?、?频、视频等资源文件。3.5寸非Retina(视网膜)屏幕(320*480)放一张全屏图片,占用字节数320*480*4(一个像素占4个字节,存放RGBA),即:600k Bytes。iPhone 3GS同时读取60张图片就会Crash。4寸屏幕(320*568),实际像素640*1136,程序存放一张全屏图片,占用字节数640*1136*4,即2.77M Bytes。iPhone 5S同时读取40张图片就会Crash。

野指针异常

对象内存空间已经被系统回收,仍然使?指针操作这块内存。野指针异常是程序crash的主要原因。代码量越?的程序,越难找出野指针的位置。了解内存管理,能帮我们提升程序性能,?大减少调试bug时间。

内存管理的?式

垃圾回收(gc):程序员只需要开辟内存空间,不需要用代码显示地释放,系统来判断哪些空间不再被使用,并回收这些内存空间,以便再次分配。整个回收的过程不需要写任何代码,由系统自动完成垃圾回收。Java开发中一直使?的就是垃圾回收技术。

人工引用计数 MRC(Manual Reference Count):内存的开辟和释放都由程序代码进?控制。相对垃圾回收来说,对内存的控制更加灵活,可以在需要释放的时候及时释放,对程序员的要求较高,程序员要熟悉内存管理的机制。

?动引用计数 ARC(Auto Reference Count):Xcode4.2及以上版本具有自动管理内存ARC机制,iOS 5.0的编译器特性,它允许用户只开辟空间,不用去释放空间。它不是垃圾回收。本质是MRC,只是编译器帮助程序员默认加了释放的代码。

iOS的内存管理

  • iOS支持两种内存管理方式:ARC 和 MRC。
  • MRC的内存管理机制是:引用计数。
  • ARC基于MRC。

二、内存管理机制及影响引用计数的方法

引用计数

实际开发中,可能会遇到两个以上的指针使用同一块内存。C语言无法记录内存使用者的个数。Objective-C采用引用计数机制管理内存,当一个新的引用指向对象时,引用计数器就递增,当去掉一个引用时,引用计数就递减。当引用计数到零时,该对象就将释放占有的资源。

影响引?计数的方法

+ alloc:开辟内存空间,让被开辟的内存空间的引用计数变为1。这是由0到1的过程。

- retain:引?计数加1,如果内存空间之前引用计数为1,retain之后变为2,如果引用计数是5,retain之后变为6。

- copy:把某一内存区域的内容拷贝一份,拷贝到新的内存空间里去,被拷贝区域的引用计数不变,新的内存区域的引用计数为1。copy可以这样理解,如果指针A和指针B不想互相牵扯,A管理A的内存,B管理B的内存。

- release:引用计数减1,如果内存空间之前引用计数为4,release之后变为3,如果之前引用计数为1,release之后变为0,内存被系统回收。

- autorelease:未来的某一时刻(程序运行出自动释放池)引用计数减1。如果内存之前引用计数为4,autorelease之后仍然为4,未来某个时刻会变为3。

- dealloc:继承自父类的方法,当对象引用计数为0的时候,由对象自动调用。在dealloc方法中对变量的释放顺序与初始化的顺序相反,在最后调用[super init]。

autoreleasepool的使?

通过autoreleasepool控制autorelease对象的释放。

向一个对象发送autorelease消息,这个对象何时释放,取决于autoreleasepool。

NSAutoreleasePool *pool= [[NSAutoreleasePool alloc] init];
Person *p = [[Person alloc] init];  //  retainCount为1
[p retain];  //  retainCount为2
[p autorelease];  //  retainCount为2 未来的某个时刻释放
[pool release];  //  此时 autorelease的对象引用计数-1
NSLog(@”%d”, [p retainCount]);  //  打印结果为1

/* NSAutoreleasePool在ARC模式下运行,会得到编译错误,而不是运行错误。作为替代,@autoreleasepool{}被引入。本例只是实现简单效果。 */

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];[pool release];就像一对括号,[xxx autorelease];必须写在两者之间。[xxx autorelease];出现在了两者之间,pool就会把接收autorelease的对象给保存起来(以栈的方式,把对象压入栈)当[pool release];的时候,pool会向之前保存的对象逐一发送release消息(对象出栈,越晚autorelease的对象,越早接收release消息)。

在iOS 5之后,不再推荐使用NSAutoreleasePool类,使用@autoreleasepool{}替代。之前写在NSAutoreleasePool *pool = [[NSAutoreleasePool

alloc] init];[pool release];之间的代码,需要写在@autoreleasepool{}的大括号里。出了大括号,自动释放池才向各个对象发送release消息。


三、内存管理的原则

引用计数的增加和减少相等,当引用计数降为0之后,不应该再使?这块内存空间。凡是使用了alloc、retain或者copy让内存的引用计数增加了,就需要使用release或者autorelease让内存的引?计数减少。在一段代码内,增加和减少的次数要相等。


四、copy

跟retain不同,一个对象想要copy,?成?己的副本,需要实现NSCopying协议,定义copy的细节(如何copy)。如果类没有接受NSCopying协议而给对象发送copy消息,会引起crash。

copy分为深copy和浅copy。我们经常使用(包括下面例子)的是浅copy,至于区别会在后续的博文中详细叙述。

copy?法的实现

Person.h?件

@interface Person : NSObject<NSCopying>

@property (nonatomic, retain) NSString *name;
@property (nonatomic, assign) int age;

@end

Person.m?件

@implementation Person

- (id)copyWithZone:(NSZone *)zone

{
  Person *p = [[Person allocWithZone:zone] init];
  p.age = self.age;
  p.name = self.name;
  return p;
}

main.m?件

Person *p = [[Person alloc] init];
p.name = @”张三”;
p.age = 20;
Person *p2 = [p copy];
//  p2是p的副本。p2.name与p.name一样。p2.age与p.age一样。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-30 16:31:33

Objective-C学习笔记_内存管理(一)的相关文章

黑马程序员_IOS开发_Objective-C学习笔记_内存管理

1.内存管理概述 1.1什么是内存管理:内存管理是程序设计中常用的资源管理的一部分,每个计算机系统可供程序使用的内存都是有限的. 1.2为什么要使用内存管理:当我们的程序运行结束的时候,操作系统将回收其我们程序占用内存.但是,只要程序还在运行,它就会一直占用内存.如果不进行及时清理不用的内存,内存最终将被耗尽.每个程序都会使用内存,我们必须确保在需要的时候分配内存,而在程序运行结束时释放占用的内存.如果我们只分配而不释放内存,将发生内存泄漏. 1.3引用计数:1.3.1只有当你对一个对象了all

Objective-C学习笔记_内存管理(二)

一.属性的内部实现原理 assign的属性内部实现 setter方法: // setter方法 @property (nonatomic, assign) NSString *name; - (void)setName:(NSString *)name { _name = name; } getter方法: // getter方法 - (NSString *)name { return _name; } 观察下面代码会出现什么问题? NSString *name = [[NSString all

linux kernel学习笔记-5内存管理(转)

http://blog.sina.com.cn/s/blog_65373f1401019dtz.htmllinux kernel学习笔记-5 内存管理1. 相关的数据结构 相比用户空间而言,在内核中分配内存往往受到更多的限制,比如内核中很多情况下不能睡眠,此外处理内存分配失败也不像用户空间那么容易.内核使用了页和区两种数据结构来管理内存: 1.1 页 内核把物理页作为内存管理的基本单位.尽管CPU的最小可寻址单位通常为字(甚至字节),但是MMU(内存管理单元,管理内存并把虚拟地址转换为物理地址的

Linux System Programming 学习笔记(九) 内存管理

1. 进程地址空间 Linux中,进程并不是直接操作物理内存地址,而是每个进程关联一个虚拟地址空间 内存页是memory management unit (MMU) 可以管理的最小地址单元 机器的体系结构决定了内存页大小,32位系统通常是 4KB, 64位系统通常是 8KB 内存页分为 valid or invalid: A valid page is associated with an actual page of data,例如RAM或者磁盘上的文件 An invalid page is

LDD读书笔记_内存管理

本部分不仅仅是LDD的介绍部分, 还包括了对linux的内存模型的总结. 一句话总结 伙伴系统是基石, slab基于伙伴系统, kmalloc基于slab. 要点 ?伙伴系统是对连续大内存而言, 得到的内存的单位从1个page到211 page, 解决外部碎片问题. ?Slab分配器是针对小内存而言, 从32B到128KB, 解决的是内部碎片问题, kmalloc是基于slab分配器的. ?如果物理内存加上需要映射的IO空间内存的大小加起来超过896M, 则有必要开启highmen的功能. Ag

计算机操作系统学习笔记_7_内存管理 --内存管理基础

h2.western { font-family: "Liberation Sans",sans-serif; font-size: 16pt; }h2.cjk { font-family: "微软雅黑"; font-size: 16pt; }h2.ctl { font-family: "AR PL UMing CN"; font-size: 16pt; }h1 { margin-bottom: 0.21cm; }h1.western { fon

计算机操作系统学习笔记_8_内存管理 --虚拟内存管理

td p { margin-bottom: 0cm; }h2.western { font-family: "Liberation Sans",sans-serif; font-size: 16pt; }h2.cjk { font-family: "微软雅黑"; font-size: 16pt; }h2.ctl { font-family: "AR PL UMing CN"; font-size: 16pt; }h1 { margin-botto

嵌入式linux学习笔记1—内存管理MMU之虚拟地址到物理地址的转化

一.内存管理基本知识 1.S3C2440最多会用到两级页表:以段的方式进行转换时只用到一级页表,以页的方式进行转换时用到两级页表.页的大小有三种:大页(64KB),小页(4KB),极小页(1KB).条目也称为"描述符",有:段描述符,大页描述符,小页描述符,极小页描述符——他们保存大页,小页,极小页的起始物理地址:粗页表描述符,细页表描述符——他们保存二级页表的物理地址. 2.一级页表描述符的最低两位,可分为以下四种情况: (1).0b00:无效. (2).0b01:粗页表. (3).

arm-linux学习笔记3-linux内存管理与文件操作

配置好linux系统之后需要vim配置一下,有助于我们的编程,主要的配置如下 在/etc/vim/vimrc文件中 "显示行号 set number "自动缩进 set autoindent "智能缩进 set smartindent "一次四格 tab set tabstop=4 "一次四格 set shiftwidth=4 "括号匹配 set showmatch "右下角显示光标状态行 set ruler "文件类型检测