Memory Management (内存管理)

来源:互联网 时间:2017-01-22


Memory Management (内存管理)

首先要知道为什么要进行内存管理?


资源最大化利用,众所周知,不管是计算机还是移动设备单片机等的内存都是有限的,如何在有限的内存空间运行更多更大的程序就是每一个内存管理系统所要考虑的问题,通过控制所有对象的生命周期,从而减少内存的占用,让程序之后不使用的对象释放自己的内存空间


怎么判断这个对象在以后的程序中不会使用了呢?


C 和 C++有严格的申请内存和释放部分,需要人为处理,有些高级的现代语言增加了 gc(garbage collection)机制去帮助开发者管理内存,当然 gc 自身程序也是消耗内存的,会在运行期间监控对象,典型的就是 java语言.
那么,我们所要讨论的的 objc 就是使用了一个叫做 retaincount(引用基数)的东东,来确定对象是否被某个对象拥有,以便确定对象是否在未来会被使用..当 retaincount 为0 时,表示对象已经完成使命,由系统自动执行 dealloc销毁...


在 xcode 4.2之前 ,都是 mrc,手动管理retaincount..以便精确控制对象的生命周期,之后就有了 arc ,在编译期间通过xcode 自动代码注入


参考
the difference between gc and arc
gc 比引用计数高明多,也占内存多,会自动破坏循环引用,而不会出现内存泄露问题(难道这也是 ios比安卓快的一个原因?哈哈)




基本的内存管理规则


The memory management model is based on object ownership. Any object may have one or more owners. As long as an object has at least one owner, it continues to exist. If an object has no owners, the runtime system destroys it automatically. <


任何对象都有拥有者,只要一个对象有至少一个拥有者,它就回一直存在(也就是只要引用计数大于1),如果没有拥有者,运行时系统就回执行对象的 dealloc 方法,销毁它


我们在使用的时候一定要拥有几个基本规则



You own any object you create
You create an object using a method whose name begins with “alloc”, “new”, “copy”, or “mutableCopy” (for example, alloc, newObject, or mutableCopy).



You can take ownership of an object using retain


A received object is normally guaranteed to remain valid within the method it was received in, and that method may also safely return the object to its invoker. You use retain in two situations: (1) In the implementation of an accessor method or an init method, to take ownership of an object you want to store as a property value; and (2) To prevent an object from being invalidated as a side-effect of some other operation (as explained in Avoid Causing Deallocation of Objects You’re Using).



When you no longer need it, you must relinquish ownership of an object you own
You relinquish ownership of an object by sending it a release messi9age or an autorelease message. In Cocoa terminology, relinquishing ownership of an object is therefore typically referred to as “releasing” an object.



You must not relinquish ownership of an object you do not own
This is just corollary of the previous policy rules, stated explicitly.




当你创建一个对象时,你就拥有一个对象 通过 alloc,copy,new 等方法..


也可以拥有对象,使用 retain 方法(有两种情况)
以下这些都是 mrc 的:
一种是作为对象的属性值,在初始化的时候 retain. 令一种是避免在基础集合类中 remove某个元素之后,还未被使用此元素就已经被销毁


heisenObject = [array objectAtIndex:n];
[array removeObjectAtIndex:n];
// heisenObject could now be invalid.

id parent = <#create a parent object#>;
// ...
heisenObject = [parent child] ;
[parent release]; // Or, for example: self.parent = nil;
// heisenObject could now be invalid.

为了避免上面情况发生,我们使用 ratain 暂时持有


heisenObject = [[array objectAtIndex:n] retain];
[array removeObjectAtIndex:n];
// Use heisenObject...
[heisenObject release];

一定要记住命名规定(naming conwention)中的规则


You Don’t Own Objects Returned by Reference
Some methods in Cocoa specify that an object is returned by reference (that is, they take an argument of type ClassName * or id ). A common pattern is to use an NSError object that contains information about an error if one occurs, as illustrated by initWithContentsOfURL:options:error: (NSData) and initWithContentsOfFile:encoding:error: (NSString).
有些返回值是一个对象 ,但是你不是拥有者,所以不要随便释放


来个 dealloc 的例子
(在最后一定要记得调用 superclass 的实现)正如 (init在开始一定要调用 superclass 的实现)


我们也要善于使用自动释放池(autorelease),每个线程只有一个自己的自动释放池,所以在建立线程时要手动创建
在循环创建很多临时对象的时候,我们可以@autorelease{}去减少内存占用


 (NSURL *url in urls) {
@autoreleasepool {
NSError *error;
NSString *fileContents = [NSString stringWithContentsOfURL:url
encoding:NSUTF8StringEncoding error:&error];
/* Process the string, creating and autoreleasing more objects. */
}
}

上面说的都是 mrc 手动管理内存的时候


现在我们说说 arc
两个都是要避免循环引用,这样会让对象一直存在




arc中我们不必关心引用计数,只需要关心拥有对象就行.


 @interface Counter : NSObject
@property (nonatomic, retain) NSNumber *count;
@end;
- (NSNumber *)count {
return _count;
}
- (void)setCount:(NSNumber *)newCount {
[newCount retain];
[_count release];
// Make the new assignment.
_count = newCount;
}
1- (void)reset {
NSNumber *zero = [[NSNumber alloc] initWithInteger:0];
[self setCount:zero];
[zero release];
}
2- (void)reset {
NSNumber *zero = [NSNumber numberWithInteger:0];
[self setCount:zero];
}

看清上面的1.2 ,和命名规则有关


Don’t Use Accessor Methods in Initializer Methods and dealloc

Q:为什么 delegate 一直是 weak ?
A:Because the object sending the delegate messages does not own the delegate?


Many times, it's the other way around, as when a controller sets itself as the delegate of a view or window: the controller owns the view/window, so if the view/window owned its delegate, both objects would be owning each other. This, of course, is a retain cycle, similar to a leak with the same consequence (objects that should be dead remain alive).


Other times, the objects are peers: neither one owns the other, probably because they are both owned by the same third object.


Either way, the object with the delegate should not retain its delegate.


在避免循环引用的时候,我们一定要分清 parent 和 children ..父 retain 子
delegation 是我们最熟悉的了 为什么用 weak 就是避免循环引用
官方文档:
Delegation is a simple and powerful pattern in which one object in a program acts on behalf of, or in coordination with, another object. The delegating object keeps a reference to the other object—the delegate—and at the appropriate time sends a message to it. The message informs the delegate of an event that the delegating object is about to handle or has just handled. The delegate may respond to the message by updating the appearance or state of itself or other objects in the application, and in some cases it can return a value that affects how an impending event is handled. The main value of delegation is that it allows you to easily customize the behavior of several objects in one central object.


The delegate of most Cocoa framework classes is automatically registered as an observer of notifications posted by the delegating object. The delegate need only implement a notification method declared by the framework class to receive a particular notification message.


mrc 说的多了
arc也就是我们现在开发随时使用的..一切 retain release autorelease 都是编译器帮助下注入代码的 .
只要关注 ownship.避免循环引用,问题就不大.




相关阅读:
Top