retain和copy还有assign的区别,以及引用计数
(2010-07-19 17:15:07)
一,retain, copy, assign区别
1. 假设你用malloc分配了一块内存,并且把它的地址赋值给了指针a,后来你希望指针b也共享这块内存,于是你又把a赋值给(assign)了b。此时a 和b指向同一块内存,请问当a不再需要这块内存,能否直接释放它?答案是否定的,因为a并不知道b是否还在使用这块内存,如果a释放了,那么b在使用这块 内存的时候会引起程序crash掉。
2. 了解到1中assign的问题,那么如何解决?最简单的一个方法就是使用引用计数(reference counting),还是上面的那个例子,我们给那块内存设一个引用计数,当内存被分配并且赋值给a时,引用计数是1。当把a赋值给b时引用计数增加到 2。这时如果a不再使用这块内存,它只需要把引用计数减1,表明自己不再拥有这块内存。b不再使用这块内存时也把引用计数减1。当引用计数变为0的时候, 代表该内存不再被任何指针所引用,系统可以把它直接释放掉。
3. 上面两点其实就是assign和retain的区别,assign就是直接赋值,从而可能引起1中的问题,当数据为int, float等原生类型时,可以使用assign。retain就如2中所述,使用了引用计数,retain引起引用计数加1, release引起引用计数减1,当引用计数为0时,dealloc函数被调用,内存被回收。
4. copy是在你不希望a和b共享一块内存时会使用到。a和b各自有自己的内存。
5. atomic和nonatomic用来决定编译器生成的getter和setter是否为原子操作。在多线程环境下,原子操作是必要的,否则有可能引起错 误的结果。加了atomic,setter函数会变成下面这样:
1. 假设你用malloc分配了一块内存,并且把它的地址赋值给了指针a,后来你希望指针b也共享这块内存,于是你又把a赋值给(assign)了b。此时a 和b指向同一块内存,请问当a不再需要这块内存,能否直接释放它?答案是否定的,因为a并不知道b是否还在使用这块内存,如果a释放了,那么b在使用这块 内存的时候会引起程序crash掉。
2. 了解到1中assign的问题,那么如何解决?最简单的一个方法就是使用引用计数(reference counting),还是上面的那个例子,我们给那块内存设一个引用计数,当内存被分配并且赋值给a时,引用计数是1。当把a赋值给b时引用计数增加到 2。这时如果a不再使用这块内存,它只需要把引用计数减1,表明自己不再拥有这块内存。b不再使用这块内存时也把引用计数减1。当引用计数变为0的时候, 代表该内存不再被任何指针所引用,系统可以把它直接释放掉。
3. 上面两点其实就是assign和retain的区别,assign就是直接赋值,从而可能引起1中的问题,当数据为int, float等原生类型时,可以使用assign。retain就如2中所述,使用了引用计数,retain引起引用计数加1, release引起引用计数减1,当引用计数为0时,dealloc函数被调用,内存被回收。
4. copy是在你不希望a和b共享一块内存时会使用到。a和b各自有自己的内存。
5. atomic和nonatomic用来决定编译器生成的getter和setter是否为原子操作。在多线程环境下,原子操作是必要的,否则有可能引起错 误的结果。加了atomic,setter函数会变成下面这样:
if (property != newValue) {
[property release];
property = [newValue retain];
}
二,深入理解一下(包括autorelease)
1. retain之后count加一。alloc之后count就是1,release就会调用dealloc销毁这个对象。
如果 retain,需要release两次。通常在method中把参数赋给成员变量时需要retain。
例如:
ClassA有 setName这个方法:
-(void)setName:(ClassName *) inputName
{
name = inputName;
[name retain]; //此处retian,等同于[inputName retain],count等于2
}
调用时:
ClassName *myName = [[ClassName alloc] init];
[classA setName:myName]; //retain count == 2
[myName release]; //retain count==1,在ClassA的dealloc中release name才能真正释放内存。
2. autorelease 更加tricky,而且很容易被它的名字迷惑。我在这里要强调一下:autorelease不是garbage collection,完全不同于Java或者.Net中的GC。
autorelease和作用域没有任何关系!
autorelease 原理:
a.先建立一个autorelease pool
b.对象从这个autorelease pool里面生成。
c.对象生成 之后调用autorelease函数,这个函数的作用仅仅是在autorelease pool中做个标记,让pool记得将来release一下这个对象。
d.程序结束时,pool本身也需要rerlease, 此时pool会把每一个标记为autorelease的对象release一次。如果某个对象此时retain count大于1,这个对象还是没有被销毁。
上面这个例子应该这样写:
ClassName *myName = [[[ClassName alloc] init] autorelease];//标记为autorelease
[classA setName:myName]; //retain count == 2
[myName release]; //retain count==1,注意,在ClassA的dealloc中不能release name,否则release pool时会release这个retain count为0的对象,这是不对的。
记住一点:如果这个对象是你alloc或者new出来 的,你就需要调用release。如果使用autorelease,那么仅在发生过retain的时候release一次(让retain count始终为1)。
[property release];
property = [newValue retain];
}
二,深入理解一下(包括autorelease)
1. retain之后count加一。alloc之后count就是1,release就会调用dealloc销毁这个对象。
如果 retain,需要release两次。通常在method中把参数赋给成员变量时需要retain。
例如:
ClassA有 setName这个方法:
-(void)setName:(ClassName *) inputName
{
name = inputName;
[name retain]; //此处retian,等同于[inputName retain],count等于2
}
调用时:
ClassName *myName = [[ClassName alloc] init];
[classA setName:myName]; //retain count == 2
[myName release]; //retain count==1,在ClassA的dealloc中release name才能真正释放内存。
2. autorelease 更加tricky,而且很容易被它的名字迷惑。我在这里要强调一下:autorelease不是garbage collection,完全不同于Java或者.Net中的GC。
autorelease和作用域没有任何关系!
autorelease 原理:
a.先建立一个autorelease pool
b.对象从这个autorelease pool里面生成。
c.对象生成 之后调用autorelease函数,这个函数的作用仅仅是在autorelease pool中做个标记,让pool记得将来release一下这个对象。
d.程序结束时,pool本身也需要rerlease, 此时pool会把每一个标记为autorelease的对象release一次。如果某个对象此时retain count大于1,这个对象还是没有被销毁。
上面这个例子应该这样写:
ClassName *myName = [[[ClassName alloc] init] autorelease];//标记为autorelease
[classA setName:myName]; //retain count == 2
[myName release]; //retain count==1,注意,在ClassA的dealloc中不能release name,否则release pool时会release这个retain count为0的对象,这是不对的。
记住一点:如果这个对象是你alloc或者new出来 的,你就需要调用release。如果使用autorelease,那么仅在发生过retain的时候release一次(让retain count始终为1)。
同步和异步的区别:假如有两个客户端连接服务端(服务器),如果为同步那么服务端可以同时处理这两个客户端的请求,如果为异步那么服务端就要客户端排队一个个等待处理请求。
同步,就是说你的程序在执行某一个操作时一直等待直到操作完成。
异步,就是说程序在执行某一个操作时,只是发出开始的指令;由另外的并行程序执行这段代码,当完成时再通知调用者。
操作系统的内存管理分成堆和栈。
在堆中分配的内存,都试用引用计数模式;在栈中则不是。
NSString 定义的对象是保存在栈中,所以它没有引用计算。看一些书上说它的引用计算会是 fffffffff 最大整数,测试的结果显示它是-1.对该对象进行 retain 操作,不好改变它的 retainCount 值。
MutableNSString 定义的对象,需要先分配堆中的内存空间,再初始化才能使用。它是采用引用计数管理内存的。对该对象做 retainCount 操作则每次增加一个。
其实,引用计数是对内存区域的空间管理方式,是应从内存块的视角去看的。任何对象都是指向它的指针,有多少个指针指向它,就有多少个引用计算。
如果没有任何指针指向该内存块了,很明显,该内存块就没有对象引用了,引用计算就是0, 系统会人为该内存区域已经空闲,于是立即清理,也就是更新一下管理堆的链表中某个标示位。
相关推荐
### retain、copy与assign的区别详解 #### 一、前言 在Objective-C中,了解`retain`、`copy`和`assign`这三个属性对于管理内存至关重要。这些属性主要用于定义对象属性时,它们决定了如何处理对象的引用。本文将...
在iOS开发中,Objective-C语言提供了@property关键字来声明属性,并且可以在属性声明时指定不同的内存管理行为,主要涉及到assign、retain和copy这三个关键字。为了深入理解这三者的区别,首先需要了解Objective-C的...
本文将详细解释`retain`和`assign`的区别,以及其他相关的属性修饰符如`readonly`、`readwrite`、`nonatomic`等,帮助读者更好地理解这些关键字的作用及其应用场景。 #### `retain`与`assign` **1. `retain`** - *...
本篇文章详细介绍了iOS开发中的一些常见属性设置,包括readwrite、readonly、retain、copy、assign以及nonatomic。 1. 可读性: - `readwrite`:这是变量的默认属性,如果没有明确指定其他属性,变量就会具有读写...
iOS 中 assign、retain、copy、weak、strong 的区别以及 nonatomic 的含义 iOS 中,在声明@property 属性时,总是要在括号中写上assign、retain、copy、weak、strong 中的一个,这些修饰符有什么区别?下面我们来...
对象的所有权和引用计数紧密相关,引用计数是跟踪对象被多少个所有者持有的指标。当一个对象被创建时,它的引用计数默认为1。每保留一次,引用计数加1;每释放一次,引用计数减1。当对象的引用计数降为0时,对象将被...
- 不同版本的 iOS 在内存管理和引用计数上的差异。 2. **内存管理方法** - `copyWithZone:` 和 `mutableCopyWithZone:` 方法的具体实现和用途。 3. **内存管理注意事项** - 在对象被销毁时如何正确清理资源,如...
在OC中,我们可以为属性指定不同的属性修饰符,如`retain`、`copy`、`assign`等,以及`readwrite`、`readonly`和`atomic`、`nonatomic`。下面将详细介绍这些修饰符的意义和用法。 ### `assign` `assign`是最简单的...
- **自动引用计数**:由编译器自动管理对象的引用计数,无需手动调用`retain`和`release`。 #### 24. 实例变量与属性的区别? - **实例变量**:类的私有成员,存储对象的状态信息。 - **属性**:提供了一种公共...
- **alloc、new、copy、retain:**这些方法会增加对象的引用计数。 - `alloc`:创建一个新的未初始化的对象,并将其引用计数设置为1。 - `new`:与`alloc`相似,但是之后还会调用`init`方法来初始化该对象。 - `...
1. **alloc与dealloc的区别以及与retain、release的关系** - **alloc**: 创建一个新的对象并分配内存空间。 - **dealloc**: 释放一个对象占用的内存空间。 - **retain**: 增加对象的引用计数。 - **release**: ...
- **`retain`/`copy`**:`retain`用于对象类型,会增加对象的引用计数;`copy`不仅会增加对象的引用计数,还会创建一个对象的副本。 - **`nonatomic`/`atomic`**:`nonatomic`表示非原子性,不保证线程安全,性能...
4. Copy:创建对象的副本,增加引用计数,主要用于深拷贝。 5. Unsafe_Unretained:与assign类似,不增加引用计数,但不安全,对象释放后指针不会自动设为nil,可能导致悬垂指针。 理解并熟练应用这些知识点对于...
在Objective-C中,内存管理主要通过引用计数(reference counting)来实现,包括retain, release, 和dealloc三个主要操作。 - retain用于增加对象的引用计数,防止被自动释放;release用于减少对象的引用计数;...
10. 属性定义时使用assign、retain、copy、nonatomic的场景: - assign通常用于基本数据类型或在委托设计模式中,防止循环引用。 - retain用于增加对象的所有权,引用计数加1。 - copy在复制对象时使用,字符串或...
`与`name = "object"`的区别:前者通过setter方法设置属性,会触发KVO(Key-Value Observing)和自动引用计数,后者直接赋值不涉及KVO和setter。 3. 关于`setAge:`代码的问题:在`setAge:`方法中,直接使用`self....
retain表示通过retain增加对象的引用计数,assign表示简单的赋值,不增加引用计数,copy则是拷贝对象。 7. NSLog的格式化字符串:正确使用NSLog输出字符串时,需要使用正确的格式化占位符,%@用于输出对象。 8. ...
assign用于基本数据类型或避免循环引用,retain用于取得对象的所有权并增加引用计数,copy用于复制对象(通常用于字符串和不可变对象),而nonatomic表示属性的访问不是原子性的,提高了性能但可能引起线程安全问题...