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 ObjectObjective-C Method
Create and have ownership of italloc/new/copy/mutableCopy group
Take ownership of itretian
Relinquish itrelease
Dispose of itdealloc
调用者持有

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被结束时.
典型应用场景: 加载或调整大量图片的时候.


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值