Obj-内存管理(Obj-Memory Management)
内存管理是任何编程语言中最重要的过程之一。 它是在需要时分配对象的内存并在不再需要时取消分配的过程。
管理对象内存是一个性能问题; 如果应用程序不释放不需要的对象,则其内存占用增加并且性能受损。
Objective-C内存管理技术大致可分为两类。
- “手动保留 - 释放”或MRR
- “自动参考计数”或ARC
“手动保留 - 释放”或MRR
在MRR中,我们通过跟踪自己的对象来明确管理内存。 这是使用一个称为引用计数的模型实现的,Foundation类NSObject与运行时环境一起提供。
MRR和ARC之间的唯一区别在于保留和释放由我们手动处理,而后者则自动处理。
下图表示内存管理在Objective-C中的工作方式示例。
A类对象的内存生命周期如上图所示。 如您所见,保留计数显示在对象下方,当对象的保留计数变为0时,对象将被完全释放,并且其内存将被释放以供其他对象使用。
首先使用NSObject中提供的alloc/init方法创建A类对象。 现在,保留计数变为1。
现在,B类保留了A类的对象,A类对象的保留计数变为2。
然后,C类制作该对象的副本。 现在,它被创建为A类的另一个实例,具有相同的实例变量值。 这里,保留计数是1而不是原始对象的保留计数。 这由图中的虚线表示。
使用release方法由C类释放复制的对象,并且保留计数变为0,因此对象被销毁。
对于初始的A类对象,保留计数为2,必须释放两次才能销毁它。 这是通过A类和B类的释放语句完成的,它们将保留计数分别减少到1和0。 最后,对象被破坏了。
MRR基本规则
我们拥有我们创建的任何对象:我们使用名称以“alloc”,“new”,“copy”或“mutableCopy”开头的方法创建对象
我们可以使用retain获取对象的所有权:通常保证接收到的对象在接收到的方法中保持有效,并且该方法也可以安全地将对象返回给它的调用者。 我们在两种情况下使用retain -
在访问器方法或init方法的实现中,获取我们想要存储为对象属性值的对象的所有权。
防止对象因某些其他操作的副作用而失效。
当我们不再需要它时,我们必须放弃对我们拥有的对象的所有权:我们通过向对象发送释放消息或自动释放消息来放弃对象的所有权。 因此,在Cocoa术语中,放弃对象的所有权通常被称为“释放”对象。
您不得放弃您不拥有的对象的所有权:这只是明确说明的先前政策规则的必然结果。
#import <Foundation/Foundation.h>
@interface SampleClass:NSObject
- (void)sampleMethod;
@end
@implementation SampleClass
- (void)sampleMethod {
NSLog(@"Hello, World! \n");
}
- (void)dealloc {
NSLog(@"Object deallocated");
[super dealloc];
}
@end
int main() {
/* my first program in Objective-C */
SampleClass *sampleClass = [[SampleClass alloc]init];
[sampleClass sampleMethod];
NSLog(@"Retain Count after initial allocation: %d",
[sampleClass retainCount]);
[sampleClass retain];
NSLog(@"Retain Count after retain: %d", [sampleClass retainCount]);
[sampleClass release];
NSLog(@"Retain Count after release: %d", [sampleClass retainCount]);
[sampleClass release];
NSLog(@"SampleClass dealloc will be called before this");
// Should set the object to nil
sampleClass = nil;
return 0;
}
当我们编译上面的程序时,我们将得到以下输出。
2013-09-28 04:39:52.310 demo[8385] Hello, World!
2013-09-28 04:39:52.311 demo[8385] Retain Count after initial allocation: 1
2013-09-28 04:39:52.311 demo[8385] Retain Count after retain: 2
2013-09-28 04:39:52.311 demo[8385] Retain Count after release: 1
2013-09-28 04:39:52.311 demo[8385] Object deallocated
2013-09-28 04:39:52.311 demo[8385] SampleClass dealloc will be called before this
“自动参考计数”或ARC
在自动引用计数或ARC中,系统使用与MRR相同的引用计数系统,但它在编译时为我们插入适当的内存管理方法调用。 强烈建议我们将ARC用于新项目。 如果我们使用ARC,通常不需要理解本文档中描述的底层实现,尽管在某些情况下它可能会有所帮助。 有关ARC的更多信息,请参阅转换到ARC发行说明。
如上所述,在ARC中,我们不需要添加release和retain方法,因为编译器会对此进行处理。 实际上,Objective-C的基本过程仍然是相同的。 它在内部使用保留和释放操作,使开发人员更容易编码而无需担心这些操作,这将减少写入的代码量和内存泄漏的可能性。
还有另一个原则叫做垃圾收集,它在Mac OS-X中与MRR一起使用,但由于它在OS-X Mountain Lion中的弃用,它还没有与MRR一起讨论过。 此外,iOS对象从未拥有垃圾收集功能。 使用ARC,OS-X中也没有使用垃圾收集。
这是一个简单的ARC示例。 请注意,这不适用于在线编译器,因为它不支持ARC。
#import <Foundation/Foundation.h>
@interface SampleClass:NSObject
- (void)sampleMethod;
@end
@implementation SampleClass
- (void)sampleMethod {
NSLog(@"Hello, World! \n");
}
- (void)dealloc {
NSLog(@"Object deallocated");
}
@end
int main() {
/* my first program in Objective-C */
@autoreleasepool {
SampleClass *sampleClass = [[SampleClass alloc]init];
[sampleClass sampleMethod];
sampleClass = nil;
}
return 0;
}
当我们编译上面的程序时,我们将得到以下输出。
2013-09-28 04:45:47.310 demo[8385] Hello, World!
2013-09-28 04:45:47.311 demo[8385] Object deallocated