ios MRC && ARC

MRC內存管理原則

1. You have ownership of any objects you create.
2. You can take ownership of an object using retain.
3. When no longer needed, you must relinquish ownership of an object you own.
4. You must not relinquish ownership of an object you don’t own.

Action for Objective-C Object Objective-C Method
Create and have ownership of it alloc/new/copy/mutableCopy group
Take ownership of it retian
Relinquish it release
Dispose of it dealloc

調用者持有

Relinquishing Ownership of a Retained Object. 下面的例子將函數將自己持有的obj, 通過return傳遞給了調用者,由調用者來來持有此變量

- (id)allocObject
{
  /*
  - You create an object and have ownership. */
  id obj = [[NSObject alloc] init];
  /*
  - At this moment, this method has ownership of the object. */
  return obj; 
}

調用者不持有

通過autorelease, 可以讓調用者不持有該對象. Autorelease offers a mechanism to relinquish objects properly when the lifetime of the objects has ended.自動釋放提供了一種, 當對象生命週期結束時,自動釋放的機制.

- (id)object
{
  id obj = [[NSObject alloc] init];
  /*
  - At this moment, this method has ownership of the object. */
  [obj autorelease];
  /*
  - The object exists, and you don’t have ownership of it. */
  return obj; 
}

autorelease

通過autorelease將對象註冊到 最近的autoReleasePool中,當pool調用drain時, 該對象的release被調用.

不要釋放, 非你持有的對象

app crash

id obj = [[NSObject alloc] init];
[obj release];
[obj release];
id obj1 = [obj0 object];
[obj1 release];

GNUstep — The alloc Method

struct obj_layout {
  NSUInteger retained; 
};
+ (id) alloc {
  int size = sizeof(struct obj_layout) + size_of_the_object; 
  struct obj_layout *p = (struct obj_layout *)calloc(1, size); 
  return (id)(p + 1);
}

動態分配地址, 並將第一個字節, 轉換爲引用計數.

GNUstep — malloc && calloc

malloc 分配的空間沒有初始化爲0, calloc分配的空間初始化爲0; calloc可以分配多個

GNUstep — The retain Method

The alloc method returns a memory block filled with zero containing a struct obj_layout header, which has a variable “retained” to store the number of references. This number is called the reference count

id obj = [[NSObject alloc] init]; 
NSLog(@"retainCount=%d", [obj retainCount]); //1
- (NSUInteger) retainCount {
  return NSExtraRefCount(self) + 1;
}

inline NSUInteger NSExtraRefCount(id anObject){
  return ((struct obj_layout *)anObject)[-1].retained;
}
- (id) retain {
  NSIncrementExtraRefCount(self);
  return self;
}
inline void NSIncrementExtraRefCount(id anObject) {
  if (((struct obj_layout *)anObject)[-1].retained == UINT_MAX - 1)
      [NSException raise: NSInternalInconsistencyException
                  format: @"NSIncrementExtraRefCount() asked to increment too far"];
 
  ((struct obj_layout *)anObject)[-1].retained++;
}

GNUstep — The release Method

- (void) release {
  if (NSDecrementExtraRefCountWasZero(self))
    [self dealloc];
}
BOOL NSDecrementExtraRefCountWasZero(id anObject) {
  if (((struct obj_layout *)anObject)[-1].retained == 0) {
    return YES;
  } 
  else {
    ((struct obj_layout *)anObject)[-1].retained--;
    return NO; 
  }
}

GNUstep — The dealloc Method

- (void) dealloc 
  NSDeallocateObject (self);
}

inline void NSDeallocateObject(id anObject) {
  struct obj_layout *o = &((struct obj_layout *)anObject)[-1];
  free(o); 
}

GNUstep — 總結

1. All Objective-C objects have an integer value called the reference count.
2. The reference count is incremented by one when one of alloc/new/copy/mutableCopy or retain is called.
3. It is decremented by one when release is called.
4. Dealloc is called when the integer counter becomes zero.

Apple’s Implementation

-retainCount 
  __CFDoExternRefOperation
  CFBasicHashGetCountOfKey

-retain 
  __CFDoExternRefOperation 
  CFBasicHashAddValue

-release 
  __CFDoExternRefOperation 
  CFBasicHashRemoveValue
int __CFDoExternRefOperation(uintptr_t op, id obj) { 
  CFBasicHashRef table = get hashtable from obj; int count;
  switch (op) {
    case OPERATION_retainCount:
      count = CFBasicHashGetCountOfKey(table, obj); 
      return count;

    case OPERATION_retain: 
      CFBasicHashAddValue(table, obj); 
      return obj;

    case OPERATION_release:
      count = CFBasicHashRemoveValue(table, obj);
      return 0 == count; 
  }
}

在GUNstep的實現中, 引用計數存放在每個obj的header部分, 而Apple的實現, 將所有的對象的引用計數存放在一個HashTable中,

GUNstep實現的好處:

  • 更少的代碼
  • 很容易控制生命週期, 因爲計數, 本身包含在每個對象中

Apple實現的好處:

  • 每個對象不必有header部分, 從而不需要考慮對齊的問題
  • 計數統一管理, 每個對象的計數都可以訪問到, 便於系統批量處理.
  • 當每個對象的內存出問題的時候, 可以通過hashTable來定位到該對象

Autorelease

Automatic Variables

當一個自動變量, 超出其作用域時, 會自動釋放.

{
 int a;
}

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.

The following steps

  1. Create an NSAutoreleasePool object.
  2. Call “autorelease” to allocated objects.
  3. Discard the NSAutoreleasePool object
1
2
3
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; id obj = [[NSObject alloc] init];
[obj autorelease];
[pool drain];

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

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.

當有太多autorelease對象時, 程序的可用內存會急劇減少. 因爲這些對象會一直存在, 直到pool被結束時.
典型應用場景: 加載或調整大量圖片的時候.


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章