Objective-C内存管理

1.内存管理中的基本问题

  1.1为什么要进行内存管理    分配在堆空间中的对象 需要手动去释放

回顾堆栈的区别                                                                          生命周期

栈空间    函数 函数中局部变量                   调用函数压栈    函数调用结束 释放  

数据段    静态变量  全局变量                      程序开始             程序结束 释放

堆:                malloc  alloc                                程序猿手动释放 free() release

  1.2内存管理的定义

内存管理就是确保开辟的堆空间被正确的释放。

内存管理中的问题:

1.内存泄露  堆空间没有释放

2. 内存崩溃 野指针 (过早释放:使用已经释放的空间

重复释放:重复释放同一个空间)

  1.3 C语言内存管理的缺陷

1 释放一个堆 ,必须保证所有使用堆的指针结束使用,避免(提前释放);

2  释放一个指针,确保指向同一个堆的指针,只有一个被释放,避免(重复释放);

3 模块化分工编程,不易明确谁来释放

4 多线程操作,不能确定哪个线程最后结束

  1.4 OC内存管理的基本原则

1.对象在完成创建的同时,内部会自动创建一个引用计数器,这个计数器,是系统用来判断是否回收对象的唯一依据,当我们的引用计数retainCount = 0的时候,系统会毫不犹豫回收当前对象

2.[对象 retain]   reatinCount + 1 ,返回self

3.[对象 release]  reatinCount - 1

4.我们的引用计数retainCount = 0时  对象就被销毁了

5.dealloc函数,当一个对象要被销毁的时候,系统会自动调用dealloc函数,通知对象你将要被销毁

内存管理原则(配对原则):只要出现了 new,alloc,retain,就一定配对出现一个release,autorelease

 1         Person * p = [[Person alloc] init];
 2         NSLog(@"%lu",p.retainCount);
 3 //        [p retain];
 4         Person * q = [p retain];
 5         NSLog(@"%lu",q.retainCount);
 6
 7         [p release];
 8         NSLog(@"%lu",p.retainCount);
 9
10         [q release];
11         NSLog(@"%lu",p.retainCount);
12         [p run];

创建一个Person类  一个p指针指向创建的对象    创建完成之后 计数器为1   创建一个q指针指向p原本指的对象 计数器+1为2

[p release] 计数器-1   [q release] 计数器再-1 此时对象释放

1 - (void)dealloc {
2     NSLog(@"人被释放了");
3     [super dealloc];
4 }

类中重写dealloc方法 则会输出 人被释放了  若开启僵尸对象检测 则[p run]报错

// 为什么最后不为0?

最后一次输出,引用计数没有变成0.

这是为什么呢?

因为该对象的内存已经被回收,而我们向一个已经被回收的对象发了一个retainCount消息,所以它的输出结果应该是不确定的,如果该对象所占的内存被复用了,那么就有可能造成程序异常崩溃。

那为什么在这个对象被回收之后,这个不确定的值是1而不是0呢?这是因为当最后一次执行release时,系统知道马上就要回收内存了,就没有必要再将retainCount减1了,因为不管减不减1,该对象都肯定会被回收,而对象被回收后,它的所有的内存区域,包括retainCount值也变得没有意义。不将这个值从1变成0,可以减少一次内存操作,加速对象的回收。

2.单个对象的内存管理

2.1.1 内存泄露的第一种情况

1     Person * p = [[Person alloc] init];
2     NSLog(@"%lu",p.retainCount);
3     Person * q = [p retain];
4     NSLog(@"%lu",q.retainCount);
5     [p release];//引用两次需要两次release  少写一次都会内存泄露
6     [q release];

 2.1.2内存泄露的第二种情况

1     Person * p2 = [[Person alloc] init];
2     NSLog(@"%lu",p2.retainCount);
3     p2 = nil;
4     [p2 release]; // [nil release]

释放前指向nil   然后release 之前的对象没有被释放

  2.2.1 野指针的提前释放

1         Person * p = [[Person alloc] init];
2         NSLog(@"%lu",p.retainCount);
3         Person * q = [p retain];
4
5         [p release];
6        // p = nil;
7         [q release];
8         //q = nil;
9         [p run]; // [nil run]  // nil 调用任何方法都不会报错

提前释放之后再用对象的方法 会形成提前释放的野指针

  2.2.2野指针的重复释放

1         Person * p = [[Person alloc] init];
2         NSLog(@"%lu",p.retainCount);
3         [p release];
4         [p release];
5 //重复释放 

释放之后 不可retain  无法起死回生

3.多个对象的内存管理

 1         // 创建Person对象
 2         Person * p = [[Person alloc] init];
 3         // 创建Car对象
 4         Car * c = [[Car alloc] init];
 5         // 让人有一辆车
 6         [p setCar:c];
 7         [p drive];
 8         [c release];
 9         [p drive];
10         // 只要p对象存在,就可以随意调用自己的方法
11         [p release];
1 //Car类成员方法的实现以及dealloc的重写
2 - (void)dealloc {
3     NSLog(@"dealloc 车被销毁了");
4     [super dealloc];
5 }
6
7 - (void)run {
8     NSLog(@"车跑起来了");
9 }
 1 //Person类成员方法的实现以及dealloc方法的重写
 2
 3 - (void)setCar:(Car *)car {
 4     //在setCar的时候,让car的retainCount+1
 5     // 目的是保证p对象存在的时候,_car对象一定存在
 6     _car = [car retain];
 7 }
 8
 9 - (Car *)car {
10     return _car;
11 }
12
13 - (void)drive {
14     [_car run];
15 }
16
17 - (void)dealloc {
18     NSLog(@"dealloc 人被销毁了");
19     // 保证p对象销毁的时候,他所持有的_car对象也被销毁,防止出现内存泄露
20     [_car release];
21     [super dealloc];
22 }

  set方法的内存管理

若两次set方法的参数都为同一对象  那么会先把对象release一次之后再retain   但release之后就释放掉了  所以要判断参数是否和对象的成员相等

 1 - (void)setCar:(Car *)car {
 2     //在setCar的时候,让car的retainCount+1
 3     // 目的是保证p对象存在的时候,_car对象一定存在
 4
 5     // 如果调用 _car = car,并且_car的retainCount=1 的情况下会出现野指针问题
 6     if (_car != car) {
 7         // 第一次运行 [nil release]
 8         [_car release];
 9         _car = [car retain];
10     }
11
12 }

set方法可以改写为如下所示。

[email protected]的参数

// 1与内存管理相关的参数

// 默认是 assign

// retain 生成符合内存管理原则的set方法

// assign 直接赋值,不考虑内存管理(一般基本数据类型)

// 2 与多线程相关的代码

// notatomic 不生成与多线程相关的代码 默认 iOS开发中用这个

// atomic 生成与多线程相关的代码 mac开发中会用到

// 3 是否生成set与get方法

// readonly 只生成get方法

// readwrite 生成get与set方法 默认

// 没有只生成set方法的参数

// 4 set与get方法名称相关的参数

// setter 设置set方法的名字(有冒号);

// getter 设置get方法的名字

5.循环引用问题

Person类有Car类的属性

Car类也有Person类的属性 就成为循环引用

.h文件中导入头文件应换成 @class 类名 的形式

前向声明 告诉系统有这样一个类

.m文件中应导入头文件 调用类的成员方法

引用关系应该一强一弱

 1 #import <Foundation/Foundation.h>
 2 #import "Person.h"
 3 #import "Car.h"
 4 int main(int argc, const char * argv[]) {
 5     @autoreleasepool {
 6         // p 1 car 1
 7         Person * p = [[Person alloc] init];
 8         Car * car = [[Car alloc] init];
 9         // p 1 car 2
10         [p setCar:car];
11         // car 2  p 1
12         [car setPerson:p];
13         // p 0 car 1
14         [p release];      //难点总结:p release之后 计数count 变为0,此时调用 p 的 dealloc 函数,随之成员变量_car release
15         // p 0  car 0
16
17         [car release];
18
19
20
21
22 //        // p 1 car 1
23 //        Person * p = [[Person alloc] init];
24 //        Car * car = [[Car alloc] init];
25 //        // p 1 car 1
26 //        [p setCar:car];
27 //        // car 1 p 2
28 //        [car setPerson:p];
29 //        // p 1 car 1
30 //        [p release];
31 //        // p 0  car 0
32 //        [car release];
33
34
35
36
37 //        // p 1 car 1
38 //        Person * p = [[Person alloc] init];
39 //        Car * car = [[Car alloc] init];
40 //        // p 1 car 2
41 //        [p setCar:car];
42 //        // car 2 p 2
43 //        [car setPerson:p];
44 //        // p 1 car 2
45 //        [p release];
46 //        // p 1 car 1
47 //        [car release];
48
49     }
50     return 0;
51 }

main.m

1 #import <Foundation/Foundation.h>
2 @class Car; // 前向声明 告诉系统有这样一个类
3 @interface Person : NSObject
4 @property (nonatomic,retain) Car * car;
5 @end

Person.h

1 #import "Person.h"
2 #import "Car.h"
3 @implementation Person
4 - (void)dealloc {
5     NSLog(@"person 被销毁了");
6     [_car release];
7     [super dealloc];
8 }
9 @end

Person.m

1 #import <Foundation/Foundation.h>
2 @class Person;
3 @interface Car : NSObject
4 @property (nonatomic,assign) Person * person;
5 @end

Car.h

1 #import "Car.h"
2 #import "Person.h"
3 @implementation Car
4 - (void)dealloc {
5     NSLog(@"car 被销毁了");
6 //    [_person release]; 弱引用 所以没有这行
7     [super dealloc];
8 }
9 @end

Car.m

未完待续。。。。。

时间: 2024-09-28 07:40:20

Objective-C内存管理的相关文章

Objective C 内存管理[转]

1  配对原则 alloc – release new – release retain - release copy – release 2  new和alloc-init的区别 (1)区别只在于alloc分配内存的时候使用了zone. 这个zone是个什么呢? 它是给对象分配内存的时候,把关联的对象分配到一个相邻的内存区域内,以便于调用时消耗很少的代价,提升了程序处理速度. (2)为什么不推荐使用new 因为若用了new,则初始化方法只能是init.这样,假如你想调用initWithFram

objective C 内存管理及属性方法详解

oc为每个对象提供一个内部计数器,这个计数器跟踪对象的引用计数,当对象被创建或拷贝时,引用计数为1,每次保持对象时,调用retain接口,引用计数加1,如果不需要这个对象时调用release,引用计数减1,当对像的引用计数为0时,系统就会释放掉这块内存,释放对象调用dealloc 当对象包含其他对象时,就得在dealloc中自己释放他们 NSObject是IOS所有类的基类 有两个基本函数,alloc和dealloc alloc类似于C++的new,dealloc类似于delete 当对象的re

iOS核心语言Objective C语言 —— 内存管理

本分享是面向有意向从事iOS开发的伙伴以及苹果产品的发烧友们,或者已经从事了iOS的开发者,想进一步提升者.如果您对iOS开发有极高的兴趣,可以与我一起探讨iOS开发,一起学习,共同进步.如果您是零基础,建议您先翻阅我之前分享的iOS开发分分钟搞定C语言系列,然后在开始Objective C语言的学习,如果您遇到问题也可以与我探讨,另外将无偿分享自己整理出来的大概400G iOS学习视频及学习资料,都是干货哦!可以新浪微博私信?关注极客James,期待与您的共同学习和探讨!!由于时间有限,每天在

Objective -C Memory Management 内存管理 第一部分

Objective -C Memory Management??内存管理??第一部分 Memory management is part of a more general problem in programming called resource management. 内存管理是资源管理的一部分. Every computer system has finite resources for your program to use. These include memory, open fi

Objective-C(内存管理)

引用计数器 每个OC对象都有一个占4个字节存储空间的引用计数器 当使用或创建一个对象时,新对象的引用计数器默认是1 retain:可以使引用计数器+1 release:可以是引用计数器-1 retainCount:获得当前的引用计数器的值 当对象被销毁时,会重写dealloc方法 -(void)dealloc { // 这句必须放在最后面 [super dealloc]; } 僵尸对象:所占内存已经被回收的对象,僵尸对象不能再使用 野指针:指向僵尸对象(不可用的内存)的指针 错误:EXC_BAD

IOS学习笔记3—Objective C—简单的内存管理

今天简述一下简单的内存管理,在IOS5.0以后Apple增加了ARC机制(Automatic Reference Counting),给开发人员带来了不少的方便,但是为了能更好的理解IOS内存管理机制,还是需要对其比较了解. 1.在OC中,每个对象都有一个保留计数,创建时每个对象都有一个初始值为1的保留计数,释放时,保留计数都为0 2.创建自动释放的对象 要求以一个方法创建对象时,以自动释放的形式返回该对象是一个很好的编程实践 +(Car *)car { Car *myCar = [[Car a

iOSDay17之内存管理

1.内存管理的方式 1> iOS应用程序出现Crash(闪退),90%的原因是因为内存问题. 2> 内存问题 野指针异常:访问没有所有权的内存,如果想要安全的访问,必须确保空间还在 内存泄露:空间使用完之后没有及时释放 过度释放:对同一块存储空间释放多次,立刻crash 内存溢出:所有存储空间被占用 3> 管理内存的三种方式 垃圾回收机制:程序员只需要开辟存储空间,系统会自动回收内存.java采用的该机制 MRC:手动引用计数机制,由开发人员开辟空间,手动添加影响引用计数增加或减少的方法

Objective-C----MRC内存管理 、 自动释放池 、 面向对象三大特性及封装 、 继承 、 组合与聚合

1 MRC练习 1.1 问题 引用计数是Objective-C语言采用的一种内存管理技术,当一个对象被创建在堆上后,该对象的引用计数就自动设置为1,如果在其它对象中的对象成员需要持有这个对象时,则该对象的引用计数被加上1,此时如果该对象被释放,内存管理程序将首先把该对象的引用计数减1,然后判断该对象的引用计数是否为0,由于其它对象在持有该对象时将引用计数加了1,所以此时该对象的引用计数减1后不为0,则内存管理程序将不会释放该对象.直到持有该对象的其它对象也被释放时,该对象的引用计数再次减1,变为

&lt;Linux内核源码&gt;内存管理模型

题外语:本人对linux内核的了解尚浅,如果有差池欢迎指正,也欢迎提问交流! 首先要理解一下每一个进程是如何维护自己独立的寻址空间的,我的电脑里呢是8G内存空间.了解过的朋友应该都知道这是虚拟内存技术解决的这个问题,然而再linux中具体是怎样的模型解决的操作系统的这个设计需求的呢,让我们从linux源码的片段开始看吧!(以下内核源码均来自fedora21 64位系统的fc-3.19.3版本内核) <include/linux/mm_type.h>中对于物理页面的定义struct page,也

objective-c(内存管理)

本文主要记录objective-c 内存管理的知识点: 1.objective-c的对象都是分配内存在堆上,与C的mallock和C++的new类似,只有int等系统变量分配内存在栈上: 2.objective-c没有java这般复杂的垃圾回收机制,它用的是引用计数,可以理解为创建该对象后,指向该对象首地址的指针是否在其他地方被引用,若增加引用则引用数加一,反之减一,当引用数为零时系统清除该变量.内部应该是堆上分配的地址重新设置为有效,也就是说可以再次分配给其他对象,存储该对象首地址的指针清除,