IOS ARC内存管理,提高效率避免内存泄露
Cocoa内存管理机制
(1)当你使用new、alloc、copy方法创建一个对象时,该对象的保留计数器值为1.当不再使用该对象时,你要负责向该对象发送一条release或autorelease消息。这样,该对象将在其使用寿命结束时被销毁。
(2)当你通过其他方法获得一个对象时,这假设该对象的保留计数器值为1,而且已经被设置为自动释放,你不需要执行任何操作来确保该对象被清理。如果你打算在一段时间内拥有该对象,这需要保留它并确保在操作完成时释放它。
(3)如果你保留了某个对象,你需要(最终)释放或自动释放该对象。必须保持retain方法和release方法的使用次数相等。
“如果我使用了new、alloc或copy方法获得一个对象,则我必须释放或自动释放该对象。”只要你记住了这条规律,你就平安无事了。
无论什么时候拥有一个对象,有两间事情必须弄清楚:怎样获得该对象的?打算拥有该对象多长时间。
Objective-C的对象生成于堆之上,生成之后,需要一个指针来指向它。
alloc:为一个新对象分配内存,并且它的引用计数为1。调用alloc方法,你便有对新对象的所有权
copy:制造一个对象的副本(克隆体),该副本的引用计数为1,调用者具有对副本的所有权
retain:使对象的引用计数加1,并且获得对象的所有权
release:使对象的引用计数减1,并且放弃对象的所有权
autorelease:使对象的引用计数在未来的某个时候减1,并且在那个时候放弃对象的所有
ARC简介
自动引用计数(ARC),是一项为Objective - C程序在编译时提供自动内存管理的功能。ARC可以让你把注意力集中在你感兴趣的代码,对象图,和你的应用程序中的对象之间的关系,让你不必再花费精力在retain和release操作上。正如下图所示,ARC可以减少开发中的内存管理步骤,简化开发。
ARC Support Iphone Os 4.0 or later.
“parent” object should maintain strong references to its “children,” and that the children should have weak references to their parents.
You need to be careful about sending messages to objects for which you hold only a weak reference. If you send a message to an object after it has been deallocated, your application will crash. You must have well-defined conditions for when the object is valid.
使 用ARC必须遵守的规则
不可以再显示调用dealloc、或实现调用retain、release、retainCount、autorelease这些方法。也不能使用@selector(retain)
, @selector(release)
,等等。
在ARC下去自定义dealloc方法不需要调用 [super dealloc]
,(实际上如果你调用了 [super dealloc]
,编译器会报错)。super的调用是由编译器自动强制执行的。
不能使用NSAllocateObject
或NSDeallocateObject
。
使用alloc
来创建对象,由ARC来管理对象运行时的释放。
不能在C语言的结构体中使用对象指针。
建议使用Objective-C的class来管理数据格式,来代替C语言的struct
。
不能隐式转换 id和void *。
你必须告诉编译器转换的类型。当你需要在obj-C的对象和Core Foundation 类型之间转换时,你可以通过函数的参数来做。详见“Managing Toll-Free Bridging”
不能使用NSAutoreleasePool
对象。
不能使用memory Zone。
因为现在Objective-C运行时已经忽略NSZone了,所以没必要再使用NSZone了
Property 属性
assign: 简单赋值,不更改索引计数(Reference Counting)。
copy: 建立一个索引计数为1的对象,然后释放旧对象(开辟新的内存地址)
retain:释放旧的对象,将旧对象的值赋予输入对象,再提高输入对象的索引计数为1
retain的实际语法为:
- - (void)setName:(NSString *)newName {
- if (name != newName) {
- [name release];
- name = [newName retain];
- // name’s retain count has been bumped up by 1
- }
- }
说了那么麻烦,其实接下来的话最重要:
如果你不懂怎么使用他们,那么就这样
·使用assign: 对基础数据类型 (NSInteger,CGFloat)和C数据类型(int, float, double, char,等等)
·使用copy: 对NSString
· 使用retain: 对其他NSObject和其子类
nonatomic关键字:
atomic是Objc使用的一种线程保护技术,基本上来讲,是防止在写未完成的时候被另外一个线程读取,造成数据错误。而这种机制是耗费系统资源的,所以在iPhone这种小型设备上,如果没有使用多线程间的通讯编程,那么nonatomic是一个非常好的选择。
iOS 5 中对属性的设置新增了strong 和weak关键字来修饰属性(iOS 5 之前不支持ARC)
strong关键字:strong 用来修饰强引用的属性;对应原来的retain。
该属性值对应 __strong 关键字,即该属性所声明的变量将成为对象的持有者。
weak关键字:weak 用来修饰弱引用的属性;对应原来的assign。
但是不同的是当对象被释放以后,对象自动赋值为nil;并且,delegate 和 Outlet 苹果推荐用weak 属性来声明。同时,如上一回介绍的 iOS 5 之前的版本是没有 __weak 关键字的,所以 weak属性是不能使用的。这种情况我们使用 unsafe_unretained。
OSMemoryNotification.h(内存警告)
- /*
- * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
- */
- #ifndef _OSMEMORYNOTIFICATION_H_
- #define _OSMEMORYNOTIFICATION_H_
- #include <sys/cdefs.h>
- /*
- ** OSMemoryNotification.h
- **
- ** Kernel-generated notification mechanism to alert registered tasks when physical memory
- ** pressure reaches certain thresholds. Notifications are triggered in both directions
- ** so clients can manage their memory usage more and less aggressively.
- **
- */
- __BEGIN_DECLS
- struct timeval;
- /*
- ** Opaque type for notification object
- */
- typedef struct _OSMemoryNotification * OSMemoryNotificationRef;
- /*
- ** Threshold values for notifications
- */
- typedef enum {
- OSMemoryNotificationLevelAny = -1,
- OSMemoryNotificationLevelNormal = 0,
- OSMemoryNotificationLevelWarning = 1,
- OSMemoryNotificationLevelUrgent = 2,
- OSMemoryNotificationLevelCritical = 3
- } OSMemoryNotificationLevel;
- /*
- ** Creation routines. Returns the created OSMemoryNotificationRef in the note param.
- ** returns: 0 on success
- ** ENOMEM if insufficient memory or resources exists to create the notification object
- ** EINVAL if the threshold is not a valid notification level
- */
- int OSMemoryNotificationCreate(OSMemoryNotificationRef *note);
- /*
- ** returns: 0 on success
- ** EINVAL if the notification is not an initialized notification object
- */
- int OSMemoryNotificationDestroy(OSMemoryNotificationRef note);
- /*
- ** Block waiting for notification
- ** returns: 0 on success, with the level that triggered the notification in the level param
- ** EINVAL if the notification object is invalid
- ** ETIMEDOUT if abstime passes before notification occurs
- */
- int OSMemoryNotificationWait(OSMemoryNotificationRef note, OSMemoryNotificationLevel *level);
- int OSMemoryNotificationTimedWait(OSMemoryNotificationRef note, OSMemoryNotificationLevel *level, const struct timeval *abstime);
- /*
- ** Simple polling interface to detect current memory pressure level
- */
- OSMemoryNotificationLevel OSMemoryNotificationCurrentLevel(void);
- /*
- ** External notify(3) string for manual notification setup
- */
- extern const charchar *kOSMemoryNotificationName;
- __END_DECLS
- #endif /* _OSMEMORYNOTIFICATION_H_ */
- <span style="text-indent: 32.15pt;">#import <libkern/OSMemoryNotification.h></span>
- - (void)didReceiveMemoryWarning{
- NSLog(@"Recieve memory warning");
- NSLog(@"~~~~~~~~~~~~~~level~~~~~~~~~~~~~~~ %d", (int)OSMemoryNotificationCurrentLevel());
- }
程序通常情况下都先调用AppDelegate中的applicationDidReceiveMemoryWarning, 然后程序会通知各ViewController,调用其didRecieveMemoryWarning方法
为单独文件指定是否使用ARC
当你迁移一个久工程到ARC模式下, -fobjc-arc
编译开关被默认的设置在所有的Objective-C 源代码上。 你可以使用-fno-objc-arc
来为特殊的class停用ARC 。在Xcode的 target的“Build Phases”标签, 打开Compile Sources group,展开源代码列表, 双击你想要修改的源代码的名字,再弹出框里输入-fno-objc-arc
,然后点Done按钮。
总结
嵌入式设备中堆栈的内存大小都有严格的限制,所以内存的管理是个大问题,在编程过程中,及时释放我们不需要的内存对象,是基本原则。设计得不优雅的程序,可能会出现一系列的,你无可预料的问题,比如内存溢出,对象过早释放,导致程序直接crash。
ARC技术虽然能提供自动引用技术,省掉了让人烦人和容易遗漏的retain,release,autorelease等操作,其工作原理是将内存操作的代码(retain,release等)自动添加到需要的位置。即底层上使用和MRC手工引用技术一样的内存管理机制,所以使用ARC简化编码工作的同时,还是同样要对内存管理有深入的了解。
ARC技术和跟随Xcode4.2一起发布的,在缺省的工程模板里可以选择是否支持ARC技术。随着 iOS 5.1 的推出,Xcode也推出了4.3版本。在该版本下,ARC 有效时的属性(@property) 定义的时候,如果不明确指定所有权关键字,那么缺省的就是 strong。而在 Xcode4.2 中,即使 strong 也要显示指定。