iOS内存管理--Core Foundation

iOS13 一次Crash定位 - 被释放的NSURL.host 每年一次的iOS升级,都会给开发者带来一些适配工作,一些原本工作正常的代码可能就会发生崩溃。 本文讲到了一种 CoreFoundation 对象的内存管理方式在iOS13上遇到的问题。 1. 问题 iOS 13 Beta 版本上,手淘出现了一个必现的崩溃: Thread 0 name: Dispatch queue: com.apple.main-thread Thread 0 Cr... 阅读详情
Core Foundation使用引用计数,对象记录使用retain的拥有者的数量,如果对象没有拥有者,它就会被释放
Core Foundation 为对象的拥有和释放定义了以下的规则:
.如果你创建了对象(直接创建或者copy另外一个对象),你拥有这个对象
。如果你从某个地方获取一个对象,你不拥有它,如果你想阻止它被释放,你必须将你自己添加为一个owner(using CFRetain)
。如果你拥有一个对象,你必须在你使用完对象以后释放拥有关系(using CFRelease)

命名约定
使用Core Foundation时有很多方式可以得到一个对象的引用,你需要知道你是否从一个函数返回值拥有一个对象以便你知道如何考虑内存管理的细节。简短来说,如果函数名包括create,copy你就拥有这个对象。如果是包括单词get,你不拥有这个对象。

实例变量和传参数,原则就是:参数接收者为了防止接收的参数意外释放,接收者在使用前必须建立参数对象的拥有关系,使用完成后,释放关系(分别使用CFRetain和CFRelease)

示例
为了防止运行时错误和内存泄漏,你必须确定在接收,传递和返回对象时贯彻Core Foundation的拥有策略。
为了明白为什么成为一个不是你创建的对象的拥有者是必要的,可以思考以下这个问题。假设你从一个对象获取了一个值,如果这个值的容器对象释放了,它与容器对象的拥有关系就会被清除,如果这个容器对象是这个值的唯一拥有者,这个值就没有拥有者了,就会被释放了。现在你拥有一个释放对象的引用,当你尝试使用它的时候,你的应用就会crash。
static CFStringRef title = NULL;

void SetTitle(CFStringRef newTitle)
{
    
CFStringRef temp = title;
    
title = CFStringCreateCopy(kCFAllocatorDefault, newTitle);
    
CFRelease(temp);
}
这个地方有个tip,就是我们使用了copy来保持对象关系,而没有使用cfretain,是因为传递进来的是一个CFString,可能不希望被我们的函数修改,我们复制一个副本来使用,确保不修改原来的值。

static CFStringRef title = NULL;
void MyFunction(CFDictionary dict, Boolean aFlag) {
    
if (!title && !aFlag) {
        
title = (CFStringRef)CFDictionaryGetValue(dict, CFSTR("title"));
        
title = CFRetain(title);
    }
    
/* Do something with title here. */
    
if (aFlag) {
        
CFRelease(title);
    }
}


Core Foundation对象的生命周期管理
Core Foundation对象的的生命周期取决于它的引用计数-一个内部的计数用来表示谁希望保存该对象。当你创建或者复制一个对象时,它的引用计数设置为1,随后的客户可以通过CFRetain把计数增加1来关联这个对象关系。随后当你不需要用这个对象的时候,你可以使用CFRelease将引用计数减少1,当引用计数达到0时,对象的allocator就释放对象的内存。

Retaining对象的引用计数
为了增加Core Foundation的引用计数,把这个对象的引用当作参数传递给CFRetain函数
/* myString is a CFStringRef received from elsewhere */
myString = (CFStringRef)CFRetain(myString);

Releasing对象的引用
为了减少Core Foundation的引用计数,把这个对象的引用当作参数传递给CFRelease函数
CFRelease(myString);

注意:你不能直接释放一个Core Foundation对象(例如调用free)。当你使用完一个对象,调用CFRelease函数,Core Foundation会正确的释放对象的。

如果你想知道Core Foundation 对象当前的引用计数,把这个对象的引用当作参数传递给CFGetRetainCount函数。
注意,事实上很少需要知道当前对象的引用计数,除非在调试时,如果你发现你需要知道一个对象retain的数量,检查你是否正确应用了关系策略规则。

复制函数
当你试图使用=来复制一个Core Foundation对象时,你需要注意你不会复制对象本身而且复制了对象的引用。
这种复制方式是很快的,因为仅仅是复制了引用地址,而没有复制对象,但是需要注意的是在可变对象上使用这种复制是很危险的。
如果你希望复制对象本身,你必须使用Core Foundation提供的函数来达到这个目的。比如CFString,你可以使用CFStringCreateCopy来创建一个与原始CFString对象完全相同的内容。Core Foundation类型同样提供了CreateMutableCopy,这个函数返回一个可以被修改的对象的副本。

浅拷贝和深拷贝
拷贝一个集合对象时候,集合对象里面包含其他的对象,需要多留心。和简单对象入CFString不同的是,createCopy函数提供给集合对象CFArray,CFSet实际执行的就是一个浅拷贝。浅拷贝就意味着集合对象创建了,但是集合里面的对象没有被复制,仅仅是对象的引用被复制到新的集合中去了。这种类型的复制是很有用的,当你处理不需要进行修改的对象时可以避免内存的浪费。

当你需要创建一个完整的集合对象时,你必须应用深拷贝。深拷贝复制集合对象同时复制集合对象里面的内容。
CFPropertyListCreateDeepCopy对一个属性列表执行深拷贝。
如果你想为其他对象创建深拷贝,你可以自己用递归下降进入到集合对象种复制所有的内容来执行深拷贝。实现这样的函数时要注意,集合对象可以递归,他们可能直接或者间接的包含他们自己的引用,这样会形成递归循环。

在创建函数中使用allocators。
每个创建函数都把allocator的引用当作第一个参数(CFAllocatorRef)。
作为参数的allocator,你有以下选择:
1. 你可以传递一个常量kCFAllocatorSystemDefault;这样指定了一般的allocator
2. 你可以传递一个NULL来指定当前默认的allocator。就相当于传递了kCFAllocatorDefault。
3. 你可以传递一个kCFAllocatorNull指出allocator不进行allocate,企图使用进行allocate的话会有一个error。有一些创建函数有一个参数为了特殊的allocator来重新分配或者释放内存。当这个参数指定为kCFAllocatorNull,你就阻止了自动再分配和释放。
4. 你可以使用CFGetAllocator从另外一个Core Foundation对象获取一个allocator的引用,然后当参数传递进去。这个计数允许你把相关的对象放进一个内存区域使用同样的allocator来分配他们。
5. 你也可以传递一个自定义的allocator的引用。 

如果你使用自定义的allocator并且你希望它成为默认的allocator。明智的做法时首先使用CFAllocatorGetDefault函数获取一个当前默认allocator的引用,然后存储到一个局部变量。当你完成使用你自定义的allocator后,使用CFAllocatorSetDefault函数重置存储的allocator为默认的allocator。

使用allocator context
在Core Foundation中每个allocator都有一个上下文。上下文是定义对象的操作环境和一些典型的函数指针的结构。
allocator的上下文由一个CFAllocatorContext结构体定义。除了函数指针,结构体包括了一些版本编号和用户自定义数据。
typedef struct {
    
CFIndex version;
    
void * info;
    
const void *(*retain)(const void *info);
    
void (*release)(const void *info);
    
CFStringRef (*copyDescription)(const void *info);
    
void * (*allocate)(CFIndex size, CFOptionFlags hint, void *info);
    
void * (*reallocate)(void *ptr, CFIndex newsize, CFOptionFlags hint, void
                         *info);
    
void (*deallocate)(void *ptr, void *info);
    
CFIndex (*preferredSize)(CFIndex size, CFOptionFlags hint, void *info);
} CFAllocatorContext;
在当前的版本中,不要把version值设置为0以外的值。

下面的代码为获取分配器上下文和用户自定义数据提供的方法。
static int numOutstandingAllocations(CFAllocatorRef alloc)
{
    
CFAllocatorContext context;
    context.
version = 0;
    
CFAllocatorGetContext(alloc, &context);
    
return (*(int*)context.info);
}

创建自定义的allocators
为了创建自己的allocator,首先声明和初始化一个CFAllocatorContext的结构体。初始化版本为0,分配和赋值需要的数据,比如控制信息给info。
一旦你已经给CFAllocatorContext各个域赋予了合适的值,调用CFAllocatorCreate函数来创建一个allocator对象。这个函数的第二个参数是一个指向结构体的指针。这个函数的第一个参数定义了一个用来为新对象分配内存的allocator。如果你想用allocatCFAllocatteContext结构体中的回调函数,指定第一个参数kCFAllocatorUseContext常量。如果你打算使用默认的allocator,指定NULL。

static CFAllocatorRef myAllocator(void) {
    
static CFAllocatorRef allocator = NULL;
    
if (!allocator) {
        
CFAllocatorContext context =
        {
0, NULL, NULL, (void *)free, NULL,
            myAlloc, myRealloc, myDealloc, 
NULL};
        context.
info = malloc(sizeof(int));
        allocator = 
CFAllocatorCreate(NULL, &context);
    }
    
return allocator;
}

实现allocator的回调函数
CFAllocatorContext结构体由7个定义回调函数的域。如果你创建一个自定义的allocator,你必须至少实现allocate函数,allocator回调函数必须是线程安全的并且,当回调函数调用其他函数时候,他们必须是可重入的。(可重入,简单来说就是不依赖传入参数和全局变量的函数)

retain,release,copyDescription等回调都把CFAllocatorContext的info当作他们的参数。void*,可以指向你为allocator定义的任何数据,如包含控制信息的结构体。

void * (*allocate)(CFIndex size, CFOptionFlags hint, void *info);
分配一块至少是size大小的内存,返回一个指向内存起始位置的指针。hint参数是你目前不能使用的位域。size参数通常必须大于0.如果这个参数不大于0,或者分配内存时候出错了,返回NULL。这个回调一般不是NULL.
iOS基础:【ARC下的内存管理】 Foundation对象与Core Foundation对象有什么区别? 前言ARC只支持管理 Objective-C 对象, 不支持 Core Foundation 对象。Core Foundation 对象必须使用CFRetain和CFRelease来进行内存管理。 那么当使用Objective-C 和 Core Foundation 对象相互转换的时候,必须让编译器知道,到底由谁来负责释放对象,是否交给ARC处理。根据不同需求,有3种转换方式 __bridge 阅读详情

相关推荐

iOS小技能:内存管理(引用计数、 ARC下内存管理的规则、桥接)

内存管理 凡是函数名中带有create、copy、new、retain等字眼的,都应该在不需要这个数据的时候进行release。 GCD的数据类型在ARC环境下不需要进行release;而CF的数据类型在ARC、MRC环境下都需要做release的 /* 内存管理的补充: 1、foundation框架 OC语言 2、core foundation 框架 1)、C语

专注于计算机研发知识和资讯分享 1万+

CFRelease 方法

CFRelease 释放掉一个类的所占的内存 声明 void CFRelease( CFTypeRef cf ); 参数 cf  一个要释放的 CFType 类,这个值一定不能为 NULL 说明 如果引用计数变为0,类的内存地址将会回收,类也将被销毁。 如果你创建,复制,或者保留一个对象,在你不需要它的时候,就有责任将它释放掉。 注意 如果 cf 为 NULL,将会导致一个运行

急需成长的路 5987

62、iOS开发中的内存管理与自动引用计数

本文深入探讨了iOS开发中的内存管理机制,包括手动内存管理和自动引用计数(ARC)的工作原理。文章详细介绍了引用计数的基本规则、常见错误类型及解决方法,并通过示例代码说明如何正确使用强引用和弱引用。此外,还分析了ARC的优势及其无法处理的情况,如与Core Foundation的交互问题。无论对于新手还是资深开发者,本文都提供了实用的内存管理技巧和最佳实践。

rust6ferris的博客 118

free 与 CFRelease 的区别

如果我们使用 creat new copy 等函数,就会开辟一段堆空间,返回一个对象。 用一个指针指向这个对象:ptr = obj;,我们要释放这块对象的内存,就可以这样做:free(ptr); ,这时在堆上的内存就已经被释放了。但这还没有完,虽然我们堆上的空间已经被释放了,但是ptr里面还是有值的,如果仍然在程序中使用ptr指针的话就会出现坏内存访问的问题。正确的做法是在free之后,再清空指...

weixin_34060299的博客 1145

飞腾X100芯片GPU状态查询

本文档对在linux系统下查看X100芯片GPU状态信息进行说明,可以帮助大家了解芯片的实时工作状态。

乌拉大喵喵 2814

利用Cesium引擎实现大疆智图B3DM三维模型的高效加载与可视化

本文详细介绍了如何利用Cesium引擎高效加载与可视化大疆智图B3DM三维模型。通过性能优化实战和典型应用场景分析,帮助开发者掌握模型预处理、渲染参数调优及高级功能实现技巧,提升大规模倾斜摄影数据的网页端展示效率。

weixin_29231725的博客 219

【Effective Objective-C 2.0读书笔记】第五章:内存管理

Objective-C语言以引用计数来管理内存,这令许多初学者纠结,要是用过以“垃圾收集器”(garbage collector)来管理内存的语言,那么更会如此。“自动引用计数”机制缓解了此问题,不过使用时有很多重要的注意事项,以确保对象模型正确,不致内存泄漏。本章提醒读者注意内存管理中易犯的错误。

freeWayWalker的专栏 1232

DaVinciCFG实战:从ARXML配置到ADC代码生成全解析

本文详细解析了使用DaVinciCFG工具进行ADC模块配置的全过程,从ARXML文件处理到代码生成与集成。重点介绍了关键参数配置、ARXML语法规则、常见错误排查及代码优化技巧,帮助开发者掌握AUTOSAR架构下ADC驱动开发,提升汽车电子系统的可靠性。

f9g0h的博客 378

CF-Release使用手册

**CF-Release** 是基于[BOSH](https://bosh.io/)部署Cloud Foundry平台的核心组件。虽然此项目已标记为“attic”,意即不再活跃维护,并推荐转向使用**cf-deployment**,但了解其历史架构仍对理解Cloud Foundry有帮助。 - **.gitignore**: 版本控制中忽略的文件列表。 - **blobstore**: 包含用于

gitblog_00543的博客 485

步科触摸屏编程

1.首先官网上下载kinco软件,然后再安装驱动,安装的方式是需要两个文件。把两个文件放到driver文件夹下面,然后设备管理器右键更新,手选driver文件夹,自动安装即可。 步科触摸屏驱动文件下载地址 2.按照步科触摸屏使用手册一步一步来建立工程 Kinco HMIware使用手册下载地址 登录界面 涉及到的是页面切换,用的是login window,然后只留下等级输入那个

MAYBE的博客 2万+

C#实战:手把手教你用SerialPort实现RS485 ModbusRTU通信(附完整代码)

本文详细介绍了如何使用C#的SerialPort类实现RS485 ModbusRTU通信,包括硬件准备、串口配置、数据收发核心逻辑及高级通信技巧。通过实战案例和完整代码,帮助开发者快速掌握工业级通信框架的构建方法,提升设备间通信的稳定性和效率。

weixin_29207533的博客 255

Core Foundation(CF), 扫盲

在cocoa application的应用中,我们有时会使用Core Foundation(CF),我们经常会在Objective-C和CF之间进行转化。系统使用arc的状态下,编译器不能自动管理CF的内存,这时候你必须使用CFRetain和CFRelease来进行CF的内存的管理。 具体的CF内存管理规则见: Memory Management Programming Guide fo

yjw179的专栏 724

华为OD面试八股真题 - 操作系统相关 - 2

华为OD技术面,操作系统相关八股真题提供详细解答,这篇博客主要涉及于进程和线程相关知识点

qq_45776114的博客 967

core-foundation-rs完全指南:如何在Rust中高效绑定macOS与iOS底层库

core-foundation-rs是一个为Rust开发者提供macOS和iOS底层库绑定的强大项目,它让开发者能够在Rust中高效地与Core Foundation等系统框架进行交互。本文将为你提供一份全面的指南,帮助你快速掌握这个工具的使用方法和最佳实践。 ## 什么是core-foundation-rs? core-foundation-rs是一个Rust绑定库,它允许开发者在Rust代

gitblog_00194的博客 891

ROS从入门到精通0-4:VSCode 搭建 ROS 工程环境

为了提高开发效率,可以先安装集成开发工具和使用方便的工具,本教程用VSCode搭建ROS工程环境

FRIGIDWINTER的博客 1万+

【精细解读】xapp585(多通道LVDS接口ADC)

xapp585的参考设计有Verilog和VHDL两种源码。

FPGA艺术家的博客 532

Objective-C 和 Core Foundation 对象相互转换的内存管理总结

iOS允许Objective-C 和 Core Foundation 对象之间可以轻松的转换,拿 NSString 和 CFStringRef 来说,直接转换豪无压力:[cpp] view plain copyCFStringRef aCFString = (CFStringRef)aNSString;  NSString *aNSString = (NSString *)aCFString;  ...

weixin_42003092的博客 172

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

ios内存管理(整理篇)

iOS内存管理机制 前言 今天学习了IOS中的内存管理机制,其中一些片段是由其他文章搬过来的,我记得有篇文章是这样写到,站在巨人的肩膀上,我只是一个整理者加了一些自己的理解 为什么要学习内存管理 虽然 ARC 帮我们解决了引用计数的大部分问题,一些年轻的 iOS 开发者仍然会做不好内存管理工作。他们甚至不能理解常见的循环引用问题,而这些问题会导致内存泄漏,最终使得应用运行缓慢或者被系统终止进程。 ...

qq_43364806的博客 738

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

[ios]Objective-C 和 Core Foundation 对象相互转换的内存管理总结 【转】

Objective-C 和 Core Foundation 对象相互转换的内存管理总结 iOS允许Objective-C 和 Core Foundation 对象之间可以轻松的转换,拿 NSString 和 CFStringRef 来说,直接转换豪无压力: [cpp] view plaincopyprint? CFStringRef a

jinjiantong的专栏 569

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

【直播】美团点评技术沙龙Online004: iOS内存管理详解

【美团点评技术沙龙Online】是美团点评技术团队推出的线上分享课程,每月2-3期,采用目前最火热的线上直播形式,邀请美团点评技术专家,面向互联网技术从业人员,分享一线...

美团技术团队 2524

关于iOS fetchSSIDInfo使用以及内存泄露

-(id)fetchSSIDInfo {     NSArray *ifs = (__bridge_transfer id)CNCopySupportedInterfaces();     //    NSLog(@"%s: Supported interfaces: %@", __func__, ifs);     id info = nil;     for (NSString *i

chwanggang的博客 655

Core Foundation 框架

Core Foundation框架 (CoreFoundation.framework) 是一组C语言接口,它们为iOS应用程序提供基本数据管理和服务功能。下面列举该框架支持进行管理的数据以及可提供的服务: 群体数据类型 (数组、集合等) 程序包 字符串管理 日期和时间管理 原始数据块管理 偏好管理 URL及数据流操作

445
上一篇: iOS内存管理--ARC
下一篇: iOS Runtime
MakeCodeClear
博客等级 码龄14年 0粉丝 11原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值