一段keychain方法内存泄漏修复记录

先来看一段代码

NSMutableDictionary *attributeQuery = [query mutableCopy];
[attributeQuery setObject: (id) kCFBooleanTrue forKey:(__bridge_transfer id) kSecReturnAttributes];
CFTypeRef attrResult = NULL;
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef) attributeQuery, &attrResult);

这段代码在Leaks中在第四行会报内存泄漏,

image

一开始还以为是第一个参数中的__bridge问题,当把__bridge改成__bridge_retained之后内存泄漏报的更严重了。

分析:
首先这里用__bridge是没有问题的,此时attributeQuery的引用计数是1,而__bridge关键字并没有牵涉到内存管理权的转移,也就是说attributeQuery
的内存还是受ARC管理,等第四行代码运行之后attributeQuery可以正常收到release消息引用计数变为0内存被系统正常回收。那这里的问题到底出在哪呢?

这时候再仔细看后面第二个参数,传递的是一个地址,可以大胆的猜测SecItemCopyMatching内部实现中对的第二个参数指向的内存做了一次retain操作:

OSStatus SecItemCopyMatching(CFDictionaryRef query, CFTypeRef * __nullable CF_RETURNS_RETAINED result) {
    ....
    if (result) {
        result = CFCreate(....); //retain here
    }
    ....
    return ....;
}

并且SecItemCopyMatching函数中也第二个参数前也明确有CF_RETURNS_RETAINED关键字,先来看看CF_RETURNS_RETAINED是什么:

#ifndef CF_RETURNS_RETAINED
#if __has_feature(attribute_cf_returns_retained)
#define CF_RETURNS_RETAINED __attribute__((cf_returns_retained))
#else
#define CF_RETURNS_RETAINED
#endif
#endif

这里有关于CF_RETURNS_RETAINED的解释。

一段keychain方法内存泄漏修复记录_第1张图片
image

意思是说有CF_RETURNS_RETAINED标记的参数或者返回值它的调用发要负责对其作release操作。
说道这里结论已经很明显了,在这段代码中由于第二个参数使用后没有release导致内存泄漏。

正确的代码应该是这样:

NSMutableDictionary *attributeQuery = [query mutableCopy];
[attributeQuery setObject: (id) kCFBooleanTrue forKey:(__bridge_transfer id) kSecReturnAttributes];
CFTypeRef attrResult = NULL;
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef) attributeQuery, &attrResult);

//after use attrResult ....
if (attrResult) {
    CFRelease(attrResult);
}

attrResult使用完之后需要将其release才行。

你可能感兴趣的:(一段keychain方法内存泄漏修复记录)