iOS的内存管理,相信大家都不陌生,之前是使用的MRC,由开发人员手动来管理内存,后来使用了ARC,来由系统管理内存。本文主要讲讲Autorelease,Core Foundation对象在内存管理方面要注意的地方。

Autorelease

提到内存管理,就不得不提autorelease,虽然我们平时开发中很少会感知到它的存在。autorelease就是自动释放的意思,如果变量使用autorelease来修饰,就表明变量的释放由系统来完成。

autoreleasepool是由runloop在开启或者唤醒的时候创建的,当runloop进入睡眠或者释放掉的时候,autoreleasepool会给pool中的所有对象发送release消息。那么,由此便引申出一个问题,如果runloop不进入睡眠或者不释放(例如:主线程,或者某些常驻线程),pool里面的对象也便不会被释放,他们会堆积在内存中,但是系统会做一些优化,如下:

- (NSMutableArray*)createArrayNoAutorelease{
id arr = [NSMutableArray arrayWithCapacity:3];
return arr;
} - (NSMutableArray*)createArrayAutorelease{
return [NSMutableArray arrayWithCapacity:3];
}

上面的两个方法都是表明的要返回NSMutableArray这个对象,但是两种写法不同,系统做的处理也不相同。

我们先调用第一个方法 createArrayNoAutorelease方法,然后使用xcode的Product->Perform Action->Assemble xxx来看看,生成如下代码:

Lfunc_begin1:
....前面省略
bl _objc_retainAutoreleasedReturnValue
.loc 2 56 14
str r0, [sp, #4]
.loc 2 57 12 is_stmt 1
ldr r0, [sp, #4]
bl _objc_retain
add r1, sp, #4
movs r2, #0
.loc 2 58 1
str r0, [sp] @ 4-byte Spill
mov r0, r1
mov r1, r2
bl _objc_storeStrong
ldr r0, [sp] @ 4-byte Reload
.loc 2 58 1 is_stmt 0
add sp, #16
Ltmp3:
pop.w {r7, lr}
b.w _objc_autoreleaseReturnValue
Ltmp4:
Lfunc_end1:

其中 objc_retainAutoreleasedReturnValue和objc_autoreleaseReturnValue主要用于优化程序运行。本来应该将返回的对象注册到autoreleasepool中,但是有了这两个函数,就可以不将对象注册到autoreleasepool中,而是直接传递给调用方,这是性能调优的一个举措。

我们再来看看调用createArrayAutorelease方法,如下:

Lfunc_begin0:
... 省略
bl _objc_retainAutoreleasedReturnValue
add r1, sp, #4
movs r2, #0
.loc 2 44 8
str r0, [sp, #4]
.loc 2 49 1 is_stmt 1
mov r0, r1
mov r1, r2
bl _objc_storeStrong
add sp, #24
pop {r7, pc}
Ltmp1:
Lfunc_end0:

现在对象被注册到了autoreleasepool中。我们可以使用:

po [NSAutoreleasePool showPools]

来看看当前autoreleasepool的状况,会发现多出了一个对象,如下图:

(我只截取了一部分)

注意:对于alloc/new/copy/mutableCopy这样的方法作为返回对象,编译器会将他们优化为createArrayNoAutorelease相同的情况

关于autoreleasepool的内部结构,实现原理等,可以参看:

http://www.cocoachina.com/ios/20150610/12093.html

Core Foundation

Core Foundation对象是一组由c语言接口,可以跟Foundation框架的OC对象相互转换。

要搞清楚Core Foundation对象的内存管理,就需要搞清楚:__bridge, __bridge_retained, __bridge_transfer; CFRetain(), CFRelease() 这几个关键词的概念。

CFRetain(), CFRelease() :Core Foundation对象的内存管理方式,跟之前MRC时代的retain和release很像。

    {
CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault, "test", kCFStringEncodingUTF8);
NSLog(@"%@", str);
CFRelease(str);
}

注意:这里要调用CFRelease(str)方法,不然会有内存泄漏。

__bridge:只做类型转换,不修改对象持有者。如下:

    {
CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault, "test", kCFStringEncodingUTF8);
NSString *obj = (__bridge NSString*)str;
NSLog(@"%@", obj);
// CFRelease(str);
}

对于从CF转换为OC对象,一定要调用CFRelease(str)方法,不然会有内存泄漏,因为只是做了简单的指针地址变换,str仍然没有释放。

来看一个野指针的例子:

    CFMutableArrayRef cfObject = NULL;
{
id obj = [[NSMutableArray alloc] init];
cfObject = (__bridge CFMutableArrayRef)obj;
CFShow(cfObject);
}
CFRelease(cfObject);

因为__bridge不持有obj对象,所以当大括号结束以后,obj被释放,cfObject就成为了野指针,在调用CFRelease方法时就会引发程序崩溃。

__bridge_retained:用于将OC对象转换为CF对象,持有者也发生改变,需要调用CFRelease方法。

__bridge_transfer:将CF对象转换为OC对象,同时将对象持有权交给ARC,不需要调用CFRelease方法,如下:

    {
CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault, "test", kCFStringEncodingUTF8);
NSString *obj = (__bridge_transfer NSString*)str;
NSLog(@"%@", obj);
// CFRelease(str);
}

所以在使用CF对象时,要特别注意内存问题。

参考文章:

https://yq.aliyun.com/articles/58964

https://juejin.im/entry/579bfdfe5bbb500064d18aca

最新文章

  1. 为何Redis要比Memcached好用(转)
  2. HDU2045/*HDU2604/*HDU2501/HDU2190 递推
  3. oracle创建用户,修改用户,删除用户等关于用户的
  4. 再探Tomcat
  5. CSS三角形广告文字
  6. 一个优秀的http实现框架
  7. nginx配置记录
  8. Spring Data JPA之Hello World
  9. 不小心用js重做了一遍贪吃蛇
  10. webrtc底层一对一连接过程探索(三)
  11. iOS网络请求-AFNetworking源码解析
  12. python全栈开发day48-jqurey自定义动画,jQuery属性操作,jQuery的文档操作,jQuery中的ajax
  13. Maven存储库
  14. Spring 什么是 IOC 控制反转 ?什么是依赖注入?spring的用处 好处 为什么要用
  15. 3D Studio Max [www]
  16. 浅谈linux系统的分区问题
  17. Sybase:解锁
  18. iOS调试技巧(debug)
  19. 从无到有开发自己的Wordpress博客主题---创建主题
  20. NIO之Channel聚集(gather)写入与分散(scatter)读取

热门文章

  1. Java之Iterator
  2. 从1.5K到18K,一个程序员的5年成长之路
  3. OpenStack_I版 1.准备过程
  4. spring+jidi读取property的配置文件
  5. 从零一起学Spring Boot之LayIM项目长成记(四) Spring Boot JPA 深入了解
  6. 英文汉语切换的导航栏,纯css制作。
  7. [SPOJ]DISUBSTR:Distinct Substrings&[SPOJ]SUBST1:New Distinct Substrings
  8. golang 详解defer
  9. 解决Android Studio 3.0导入module依赖后unable to merge index
  10. 如何使用Vue