objective-c - NSGarbageCollector的disableCollectorForPointer是: calls balanced by enableCollectorForPointer: calls?

标签 objective-c cocoa garbage-collection

情况:

我需要将 Objective-C 对象作为不透明引用 (void*) 传递给异步 C API,稍后该引用将传递给我提供的回调函数。然后回调调用该对象的方法。代码需要在存在垃圾回收的情况下工作,并且在我调用 C API 和调用回调之间,不得对对象进行 GC。

NSGarbageCollector 类提供 disableCollectorForPointer:enableCollectorForPointer:用于将对象标记和取消标记为不可收集根的方法。

问题:

我无法从文档和网络搜索中得出的是,是否对 disableCollectorForPointer: 的调用进行计数,并且必须通过相同数量的 enableCollectorForPointer: 进行平衡> 来电。如果情况并非如此,并且每个对象要么被标记为根,要么未被标记为根,则在我的回调中调用 enableCollectorForPointer: 可能会清除由其他代码设置的现有根标记,从而导致要收集的对象,即使不应该收集!

我看到的替代方案是使用 CFRetainCFRelease - 这些在我自己的 NSObject 子类上使用安全吗?我之前只在免费桥接的 CF 对象上使用过这些函数。

提供证据的答案可加分。我看到到处都推荐 disableCollectorForPointer: ,但没有提到这个安全方面。

注释:

  • 我必须支持垃圾收集,因为此代码将由系统首选项的 PrefPane 使用。 PrefPane 的 64 位版本必须使用垃圾收集。因此,使用 ARC 或手动重新计数不是一种选择。
  • C API 是 Apple 的 API (IOKit) 之一,因此我也无法控制它。

最佳答案

我想我已经找到答案了。垃圾收集器的源代码似乎不可用,但声明 NSGarbageCollector 接口(interface)的头文件, 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 ,它给出以下输出,确认启用/禁用CollectorForPointer:调用确实被计数:

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

关于objective-c - NSGarbageCollector的disableCollectorForPointer是: calls balanced by enableCollectorForPointer: calls?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10738722/

相关文章:

objective-c - 相当于 IB 中自动调整大小蒙版锚定选项的代码是什么?

java - 内部类与静态嵌套类的 GC 性能下降

ios - 在 xcode 的 Tabbar 中创建显示案例 View

objective-c - 使异步 Cocoa 类以同步方式工作

objective-c - 在 iphone 中全局访问整数和字符串?

objective-c - 来自类 X 的 bool 值在从类 Y 的 View Controller 更改为类 Z 的 View ​​ Controller 之间不会持续存在

macos - 如何使虚线可移动

objective-c - 如何将 NSTimeInterval 对象传递给 detachNewThreadSelector withObject 参数?

java - 如果 Activity 具有在其他地方引用的静态成员变量,可以将其垃圾回收吗?

c# - 为什么委托(delegate)函数引用在作为参数传递时会被垃圾收集?