情况:
我需要将Objective-C对象作为不透明引用(void*
)传递给异步C API,稍后将其传递给我提供的回调函数。然后回调调用对象上的方法。代码需要在存在垃圾收集的情况下工作,并且在我调用C API和调用它的回调之间,对象不能是GC。
NSGarbageCollector
类提供了disableCollectorForPointer:
和enableCollectorForPointer:
方法,用于将对象标记和取消标记为无法收集的根。
问题:
我无法从文档中搜索并搜索网络的是disableCollectorForPointer:
的来电是否被计算在内并且必须通过相同数量的enableCollectorForPointer:
来电平衡。如果这是不的情况,并且每个对象都标记为root,则在我的回调中调用enableCollectorForPointer:
可能会清除由某些其他代码设置的现有根标志,从而导致该对象成为即使它不应该收集!
我见过的替代方法是使用CFRetain
和CFRelease
- 这些在我自己的NSObject
子类中使用是否安全?我之前只在免费桥接的CF对象上使用过这些函数。
提供证据的答案的奖励积分。我看到disableCollectorForPointer:
遍布整个地方,没有提到这个安全方面。
备注:
答案 0 :(得分:1)
我想我找到了答案。垃圾收集器的源代码似乎不可用,但是从NSGarbageCollector
声明NSGarbageCollector.h
,Foundation.framework
的接口的头文件包含以下内容:
// references outside the heap, globals, and the stack, e.g. unscanned memory, malloc memory, must be tracked by the collector
- (void)disableCollectorForPointer:(void *)ptr; // this pointer will not be collected...
- (void)enableCollectorForPointer:(void *)ptr; // ...until this (stacking) call is made
请注意“堆叠”评论 - 我认为这意味着确实计算了来电?更多证据仍然受到欢迎!
<强>更新强>
为了确定,我决定使用一个小测试程序( gcbridgetest.m )测试我的假设:
#import <Foundation/Foundation.h>
@interface PJGarbageCollectionTest : NSObject
@end
@implementation PJGarbageCollectionTest
- (id)init
{
self = [super init];
if (!self) return nil;
NSLog(@"%@ -init", self);
return self;
}
- (void)finalize
{
NSLog(@"%@ -finalize", self);
[super finalize];
}
@end
static void* ext_ptr1 = NULL;
static void* ext_ptr2 = NULL;
static void create()
{
PJGarbageCollectionTest* test = [[PJGarbageCollectionTest alloc] init];
[[NSGarbageCollector defaultCollector] disableCollectorForPointer:test];
ext_ptr1 = test;
[[NSGarbageCollector defaultCollector] disableCollectorForPointer:test];
ext_ptr2 = test;
}
static void killref(void** ext_ptr)
{
[[NSGarbageCollector defaultCollector] enableCollectorForPointer:*ext_ptr];
*ext_ptr = NULL;
}
int main()
{
NSLog(@"collector: %@", [NSGarbageCollector defaultCollector]);
create();
NSLog(@"Collecting with 2 external references");
[[NSGarbageCollector defaultCollector] collectExhaustively];
killref(&ext_ptr1);
NSLog(@"Collecting with 1 external reference");
[[NSGarbageCollector defaultCollector] collectExhaustively];
killref(&ext_ptr2);
NSLog(@"Collecting with 0 external references");
[[NSGarbageCollector defaultCollector] collectExhaustively];
return 0;
}
使用gcc -fobjc-gc-only -g -Wall -Wextra -ObjC gcbridgetest.m -framework Foundation -o gcbridgetest
编译并运行为./gcbridgetest
,它提供以下输出,确认启用/ disableCollectorForPointer:调用确实已计算在内:
2012-06-12 16:08:08.278 gcbridgetest[29712:903] collector: <NSGarbageCollector: 0x20000f420>
2012-06-12 16:08:08.281 gcbridgetest[29712:903] <PJGarbageCollectionTest: 0x20000ee60> -init
2012-06-12 16:08:08.284 gcbridgetest[29712:903] Collecting with 2 external references
2012-06-12 16:08:08.285 gcbridgetest[29712:903] Collecting with 1 external reference
2012-06-12 16:08:08.286 gcbridgetest[29712:903] Collecting with 0 external references
2012-06-12 16:08:08.286 gcbridgetest[29712:903] <PJGarbageCollectionTest: 0x20000ee60> -finalize