Implementing Autorelease
来源:互联网 发布:p2p网络借贷新闻 编辑:程序博客网 时间:2024/06/14 01:26
Autorelease
Because of its name, you might think that autorelease is something like ARC. But it is not. It is more like “automatic variable” in the C language.7
Let’s start by reviewing what automatic variable is in C. We then look at the source code of GNUstep to understand how autorelease works, followed by Apple’s implementation of autorelease.
Automatic Variables
An automatic variable is a lexically scoped variable, which is disposed of automatically when the execution leaves the scope.
{
int a;
}
/*
* Because the variable scope is left,
* auto variable 'int a' is disposed of and can't be accessed anymore.
*/
With autorelease, you can use objects in the same manner as automatic variables, meaning that when execution leaves a code block, the “release” method is called on the object automatically. You can control the block itself as well.
__________
7 Wikipedia, “Automatic Variable,” http://en.wikipedia.org/wiki/Automatic_variable
The following steps and Figure 1–12 show you how to use the “autorelease” instance method.
- Create an NSAutoreleasePool object.
- Call “autorelease” to allocated objects.
- Discard the NSAutoreleasePool object.
A code block between the creation and disposal of the NSAutoreleasePool object is equivalent to the variable scope in C. When an NSAutoreleasePool object is disposed of, the release method is automatically called for all the autoreleased objects. Some example source code is as follows.
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
id obj = [[NSObject alloc] init];
[obj autorelease];
[pool drain];
In the last line of the above source code, [pool drain] will do [obj release].
In the Cocoa Framework, NSAutoreleasePool objects are created, owned, or disposed of all over the place, such as NSRunLoop, which is the main loop of the application (Figure 1–13). So, you don’t need to use the NSAutoreleasePool object explicitly.
But when there are too many autoreleased objects, application memory becomes short (Figure 1–14). It happens because the objects still exist until the NSAutoreleasePool object is discarded. A typical example of this is loading and resizing many images. Many autoreleased objects, such as NSData objects for reading files, UImage objects for the data, and resized images exist at the same time.
for (int i = 0; i < numberOfImages; ++i) {
/*
* Processing images, such as loading,etc.
* Too many autoreleased objects exist,
* because NSAutoreleasePool object is not discarded.
* At some point, it causes memory shortage.
*/
}
In this case, you should create and discard an NSAutoreleasePool object by yourself explicitly at the appropriate time (Figure 1–15).
for (int i = 0; i < numberOfImages; ++i) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
/*
* Loading images, etc.
* Too many autoreleased objects exist.
*/
[pool drain];
/*
* All the autoreleased objects are released by [pool drain].
*/
}
With the Cocoa Framework, you will see many class methods returning autoreleased objects, such as the “arrayWithCapacity” method of the NSMutableArray class.
id array = [NSMutableArray arrayWithCapacity:1];
The above source code is equivalent to:
id array = [[[NSMutableArray alloc] initWithCapacity:1] autorelease];
Implementing autorelease
In this section, we discuss the implementation of autorelease
in GNUstep as we did foralloc
, retain
, release
, and dealloc
to learn how it works in detail.
[obj autorelease];
This source code calls the NSObject instance method “autorelease”. Listing 1–9 shows the implementation of the autorelease method.
- (id) autorelease
{
[NSAutoreleasePool addObject:self];
}
Actually, autorelease just calls the NSAutoreleasePool class method addObject. In GNUstep, it is implemented bit different. But this is just for optimization as you can see below.
OPTIMIZATION ON OBJECTIVE-C METHOD CALL
Let’s see the implementation of the NSAutoreleasePool class. Listing 1–10 is a simplified source code in NSAutoreleasePool.
+ (void) addObject: (id)anObj
{
NSAutoreleasePool *pool = getting active NSAutoreleasePool;
if (pool != nil) {
[pool addObject:anObj];
} else {
NSLog(@"autorelease is called without active NSAutoreleasePool.");
}
}
The Class method “addObject” calls NSAutoreleasePool instance method “addObject” for the active NSAutoreleasePool object. In the next example, a variable “pool” is the active NSAutoreleasePool object.
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
id obj = [[NSObject alloc] init];
[obj autorelease];
When multiple NSAutoreleasePool objects are created and nested, the innermost object becomes active. In the next example, pool2 is active.
NSAutoreleasePool *pool0 = [[NSAutoreleasePool alloc] init];
NSAutoreleasePool *pool1 = [[NSAutoreleasePool alloc] init];
NSAutoreleasePool *pool2 = [[NSAutoreleasePool alloc] init];
id obj = [[NSObject alloc] init];
[obj autorelease];
[pool2 drain];
[pool1 drain];
[pool0 drain];
Next, let’s take a look at the implementation of the NSAutoreleasePool instance method addObject as well (Listing 1–11).
- (void) addObject: (id)anObj
{
[array addObject:anObj];
}
It adds the object to a mutable array. In the original GNUstep implementation, linked list is used instead of array. Anyway, the object is stored in a container, which means that when the instance method “autorelease” of NSObject is called, the object is added to the container in an active NSAutoreleasePool object.
[pool drain];
Next, let’s see how the active NSAutoreleasePool object is disposed of when drain is called (Listing 1–12).
- (void) drain
{
[self dealloc];
}
- (void) dealloc
{
[self emptyPool];
[array release];
}
- (void) emptyPool
{
for (id obj in array) {
[obj release];
}
}
We can see that the “release” method is called for all the objects in the pool.
Apple’s Implementation of autorelease
We can see Apple’s implementation of autorelease in runtime/objc-arr.mm in the objc4 library. The source code is shown in Listing 1–13.
class AutoreleasePoolPage
{
static inline void *push()
{
/* It corresponds to creation and ownership of an NSAutoreleasePool object */
}
static inline void pop(void *token)
{
/* It corresponds to disposal of an NSAutoreleasePool object */
releaseAll();
}
static inline id autorelease(id obj)
{
/* It corresponds to NSAutoreleasePool class method addObject. */
AutoreleasePoolPage *autoreleasePoolPage = /* getting active AutoreleasePoolPage
object */
autoreleasePoolPage->add(obj);
}
id *add(id obj)
{
/* add the obj to an internal array; */
}
void releaseAll()
{
/* calls release for all the objects in the internal array */
}
};
void *objc_autoreleasePoolPush(void)
{
return AutoreleasePoolPage::push();
}
void objc_autoreleasePoolPop(void *ctxt)
{
AutoreleasePoolPage::pop(ctxt);
}
id objc_autorelease(id obj)
{
return AutoreleasePoolPage::autorelease(obj);
}
The functions and the AutoreleasePoolPage class are implemented using a C++ class and a dynamic array. The functions seem to work the same as in GNUstep. As we didpreviously with the debugger, we investigate what functions are called in the autorelease and NSAutoreleasePool class methods. These methods will call objc4 functions, which are related to autorelease:
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
/* equivalent to objc_autoreleasePoolPush() */
id obj = [[NSObject alloc] init];
[obj autorelease];
/* equivalent to objc_autorelease(obj) */
[pool drain];
/* equivalent to objc_autoreleasePoolPop(pool) */
By the way, in iOS, the NSAutoreleasePool class has a method to check the status of autoreleased objects. The method, showPools, displays the current status of NSAutoreleasePool to the console. It can be used only for debugging purposes because it is a private method. You can use it as
[NSAutoreleasePool showPools];
With the latest Objective-C runtime, instead of the “showPools” method,_objc_autoreleasePoolPrint()
is provided because “showPools” works in iOS only, This method is also a private method so you can use it for debugging purposes only.
/* declare function */
extern void _objc_autoreleasePoolPrint();
/* display autoreleasepool status for debug. */
_objc_autoreleasePoolPrint();
Then you can see the status of AutoreleasePoolPage. The result is as follows.
objc[14481]: ##############
objc[14481]: AUTORELEASE POOLS for thread 0xad0892c0
objc[14481]: 14 releases pending.
objc[14481]: [0x6a85000] ................ PAGE (hot) (cold)
objc[14481]: [0x6a85028] ################ POOL 0x6a85028
objc[14481]: [0x6a8502c] 0x6719e40 __NSCFString
objc[14481]: [0x6a85030] ################ POOL 0x6a85030
objc[14481]: [0x6a85034] 0x7608100 __NSArrayI
objc[14481]: [0x6a85038] 0x7609a60 __NSCFData
objc[14481]: [0x6a8503c] ################ POOL 0x6a8503c
objc[14481]: [0x6a85040] 0x8808df0 __NSCFDictionary
objc[14481]: [0x6a85044] 0x760ab50 NSConcreteValue
objc[14481]: [0x6a85048] 0x760afe0 NSConcreteValue
objc[14481]: [0x6a8504c] 0x760b280 NSConcreteValue
objc[14481]: [0x6a85050] 0x760b2f0 __NSCFNumber
objc[14481]: [0x6a851a8] ################ POOL 0x6a851a8
objc[14481]: [0x6a851ac] 0x741d1e0 Test
objc[14481]: [0x6a851b0] 0x671c660 NSObject
objc[14481]: ##############
It is very useful to know if some objects are autoreleased or not, as noted in the following sidebar.
AUTORELEASE NSAUTORELEASEPOOL OBJECT
- Implementing Autorelease
- autorelease
- autorelease
- autorelease
- autorelease
- @autorelease
- autorelease
- Autorelease
- Autorelease
- autorelease
- autorelease
- autorelease
- release,autorelease,autorelease pool
- Implementing IMSAdminBaseSink
- Implementing FSD_GetVolumeInfo
- Implementing graphics
- Implementing Inheritance
- Implementing Controllers
- win server 2003 X64安装.NET4.0遇到阻滞问题解决
- 对volatile关键字的理解
- 批处理切换当前目录的做法
- GDI+ 基础知识入门
- Hibernate注解方法使用主键生成策略@GeneratedValue(三)
- Implementing Autorelease
- j2ee中文乱码问题
- AIX系统errpt详解
- 深入剖析TCP协议的send与recv
- Linux 2.6内核中新的锁机制--RCU
- 『常识』UML类图关系大全
- 常见面试算法汇总---链接
- ZOJ-1514
- Android中LocalSocket使用