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 files, and network connections. If you use a resource, such as by opening a file, you need to clean up after yourself (in this case, by closing the file).
每个电脑资源有限。包括内存,打开文件数,网络连接。如果你打开了一个文件,就应该清理掉。
Our friends in
the Java and scripting worlds have it easy: memory management happens automatically for them, like having their parents clean up their rooms.
java 和它的脚本世界很容易:内存管理对他们是自动的。就像父亲收拾孩子的房间一样。
If we allocate without freeing, we'll leak memory: our program's memory consumption will grow and grow until we run out of memory, and then, the program will crash.
如果分配了内存,却没有回收,那么可能导致内存泄露:我们的程序占用越来越多的内存,直至用完内存,程序崩溃。
1.1 Object Life Cycle 对象声明周期
Just like the birds and the bees out here in the real world, objects inside a program have a life cycle. They're born (via alloc or new); they live (receive messages and do stuff), make friends (via composition and arguments to methods), and eventually die (get freed) when their lives are over. When that happens, their raw materials (memory) are recycled and used for the next generation.
就像现实世界的鸟和蜜蜂一样,在一个程序内部的对象也有生命周期。他们诞生(通过 alloc 和new) ,他们生活(接受消息和东西),他们交朋友(通过组合和参数方法)并最终死去。这样他们原来的材料(内存)被回收再利用。 说的和人一样啊啊啊。
1.2 Reference Counting
Cocoa uses a technique known as reference counting, also sometimes called retain counting.
利用引用计数或者保留计数。
Every object has an integer associated with it, known as its reference count or retain count.
每个对象都有自己的引用计数
When some chunk of code is interested in an object, the code increases the object's retain count, saying, "I am interested in this object." When that code is done with the object, it decreases the retain count, indicating that it has lost interest in that object.
有代码对一个对象感兴趣,就增加retain count。如果处理完了,就减少retain count。
When the retain count goes to 0, nobody cares about the object anymore (poor object!), so it is destroyed and its memory is returned to the system for reuse.
当retain count 是0时,就等着被回收或处理吧。
When an object is about to be destroyed because its retain count has reached 0, Objective-C automatically sends the object a dealloc message.
如果一个对象将被销毁因为retain count 到达了0
To find out the current retain count, send the retainCount message. Here are the signatures for retain, release and retainCount:
- (id) retain;
- (oneway void) release;
- (NSUInteger) retainCount;
A retain call returns an id. This enables you to chain a retain call with other message sends, incrementing the object's retain count and then asking it to do some work. For instance, [[car retain] setTire: tire atIndex: 2]; asks car to bump up its retain count and perform the setTire action.
一个retain 调用能增加retain count,然后要求它做一些工作。
1.3 Object ownership
When something is said to "own an object," that something is responsible for making sure the object gets cleaned up.
当你说你拥有这个对象的时候,那么你也要为他擦屁股。:-)
1.4 Retaining and releasing in accessor
- (void) setEngine: (Engine *) newEngine
{
engine = [newEngine retain];
// BAD CODE: do not steal. See fixed version below.
} // setEngine
Engine *engine1 = [Engine new]; // count: 1
[car setEngine: engine1]; // count: 2
[engine1 release]; // count: 1
Engine *engine2 = [Engine new]; // count: 1
[car setEngine: engine2]; // count: 2
Oops! We have a problem with engine1 now: its retain count is still 1.
engine1 的retain count 仍然是1.main()已经释放了它对engine1的索引,但是Car不会。
Here's another attempt at writing setEngine:.
另外一种形式的setEngine方法
- (void) setEngine: (Engine *) newEngine
{
[engine release];
engine = [newEngine retain];
// More BAD CODE: do not steal. Fixed version below.
} // setEngine
Engine *engine = [Engine new]; // count: 1
Car *car1 = [Car new];
Car *car2 = [Car new];
[car1 setEngine: engine]; // count: 2
[engine release]; // count 1
[car2 setEngine: [car1 engine]]; // oops!
[car1 engine] returns a pointer to engine, which has a retain count of 1. The first line of setEngine is [engine release], which makes the retain count 0, and the object gets deallocated.
[car1 engine]返回一个指针到engine,它的retain count 是1 。而setEngine 的第一行是release engine 。因此retain count 是0.因此对象被重新分配。
Here's a better way to write setEngine:
这个setEngine 比较好:
- (void) setEngine: (Engine *) newEngine
{
[newEngine retain];
[engine release];
engine = newEngine;
} // setEngine
In your accessors, if you retain the new object before you release the old object, you'll be safe.
在存储中,如果你保留新的对象在你释放久的对象之前。那么你就安全了。
1.5Autorelease 自动释放
cocoa has the concept of the autorelease pool .
cocoa 有自动释放池的概念。
The name provides a good clue.
It's a pool (collection) of stuff, presumably objects, that automatically gets released.
从名字可以看出它大概是自动释放的东西。
NSObject provides a method called autorelease:
- (id) autorelease;
This method schedules a release message to be sent at some time in the future. The return value is the object that receives the message; retain uses this same technique, which makes chaining together calls easy. When you send autorelease to an object, that object is actually added to
an autorelease pool. When that pool is destroyed, all the objects in the pool are sent a release message.
这个方法计划了一个释放信号被送出。 当你发出autorelease 给一个对象,该对象将加入autorelease pool .当pool 被释放,所有在这个pool中得对象将被发出释放信息。
- (NSString *) description
{
NSString *description;
description = [[NSString alloc]
initWithFormat: @"I am %d years old", 4];
return ([description autorelease]);
} // description
So you can write code like this:
NSLog (@"%@", [someObject description]);
1.6 销毁的前夕 The Eve of Our Destruction
When does the autorelease pool get destroyed so that it can send a release message to all the objects it contains? For that matter, when does a pool get created in the first place?
什么时候自动释放池被销毁,什么时候资源池被创建?
There are two ways you can create an autorelease pool.
有两种方式创建:
(1)Using the @autoreleasepool language keyword.
(2)Using the NSAutoreleasePool object.
第一种:@ autoreleasepool{} 。大括号里面的将放到新的pool中。
The second, and more explicit, method is to use the NSAutoreleasePool object. When you do this, the code between new and release gets to use the new pool.
第二种,用NSAutoreleasePool
NSAutoreleasePool *pool;
pool = [NSAutoreleasePool new];
...
[pool release];
int main (int argc, const char *argv[])
{
NSAutoreleasePool *pool;
pool = [[NSAutoreleasePool alloc] init];
RetainTracker *tracker;
tracker = [RetainTracker new]; // count: 1
[tracker retain]; // count: 2
[tracker autorelease]; // count: still 2
[tracker release]; // count: 1
NSLog (@"releasing pool");
[pool release];
// gets nuked, sends release to tracker
@autoreleasepool
{
RetainTracker *tracker2;
tracker2 = [RetainTracker new]; // count: 1
[tracker2 retain]; // count: 2
[tracker2 autorelease]; // count: still 2
[tracker2 release]; // count: 1
NSLog (@"auto releasing pool");
}
return (0);
} // main
[tracker autorelease]; // count: still 2
Then the object gets autoreleased. Its retain count is unchanged: it's still 2. The important thing to note is that the pool that was created earlier now has a reference to this object.
这个对象获得自动释放了。它的retain count 仍是2。但重要的是pool 有这个对象的一个reference了。